목록이 아닌 F #에서 시퀀스를 사용하는 경우


82

나는 이해 리스트가 실제로 값을 포함하고, 순서 의 별칭입니다 IEnumerable<T>. 실제 F # 개발에서 목록이 아닌 시퀀스를 언제 사용해야합니까?

시퀀스가 더 나은시기를 알 수있는 몇 가지 이유는 다음과 같습니다.

  • .NET이 필요한 다른 .NET 언어 또는 라이브러리와 상호 작용할 때 IEnumerable<T>.
  • 무한 시퀀스를 표현해야합니다 (실제로 실제로 유용하지 않을 수 있음).
  • 게으른 평가가 필요합니다.

다른 사람이 있습니까?


3
무한 시퀀스는 매우 유용하고 일반적입니다. 예를 들어 System.Random.Next ()는 이미 위장 된 "무한 시퀀스"입니다. 종종 필요한만큼 많은 요소를 생성하는 무언가를 원합니다. 저는 최근에 F #으로 Tetris를 작성했고 블록 생성을 무한 시퀀스로 표현했습니다. 게임이 진행되는 동안 필요한만큼 생성됩니다.
Asik

2
@Dr_Asik seq그런 식으로 생성 된은 볼 때마다 다른 난수 를 생성 합니다. 분명히 비 결정적 버그의 원인이 될 수 있습니다 ...
JD

답변:


96

언제 선택할지에 대한 요약 Seq이 꽤 좋다고 생각합니다 . 다음은 몇 가지 추가 사항입니다.

  • Seq함수를 작성할 때 기본적으로 사용 합니다. 모든 .NET 컬렉션에서 작동하기 때문입니다.
  • 또는 Seq같은 고급 기능이 필요한 경우 사용하십시오.Seq.windowedSeq.pairwise

Seq기본적으로 선택 하는 것이 최선의 선택이라고 생각하는데 언제 다른 유형을 선택해야합니까?

  • 사용 List하면 사용하여 처리하는 재귀 필요로 할 때 head::tail패턴
    (표준 라이브러리에서 사용할 수없는 몇 가지 기능을 구현하는)

  • List단계별로 구축 할 수있는 단순 불변 데이터 구조가 필요할 때 사용 합니다
    (예를 들어, 한 스레드에서 목록을 처리해야하는 경우-일부 통계를 표시하기 위해-동시에 수신 할 때 다른 스레드에서 목록 작성을 계속해야하는 경우). 더 많은 값, 즉 네트워크 서비스에서)

  • List짧은 목록으로 작업 할 때 사용 합니다. 목록은 값이 빈 목록을 나타내는 경우 사용하기에 가장 좋은 데이터 구조 입니다. 해당 시나리오에서 매우 효율적이기 때문입니다.

  • Array값 유형의 대규모 컬렉션이 필요할 때 사용 합니다
    (배열은 데이터를 플랫 메모리 블록에 저장하므로이 경우 메모리 효율성이 더 높습니다).

  • Array임의 액세스 또는 더 많은 성능 (및 캐시 지역성)이 필요할 때 사용 합니다.


1
대단한 감사합니다-정확히 내가 추구했던 것. 유사한 기능을 제공하는이 두 가지 요소 (list & seq)가있는 이유를 알아보기 위해 F #을 배울 때 혼란 스럽습니다.
dodgy_coder

3
" 단계별 [...]을 구축 하고 동시에 다른 스레드 에서 목록계속 구축 할 수 List있는 간단한 불변 데이터 구조 가 필요할 때 [...]를 사용하십시오 [... ]"에 대해 자세히 설명해 주시겠습니까? 여기서 의미 / 어떻게 작동합니까? 감사.
Narfanar 2015

2
아이디어는 @Noein 당신은 목록으로 초과 항상 반복 할 수 (그들은 불변)하지만 당신은 사용하여 새 목록을 만들 수 있습니다 x::xs반복의 과정에있을 수 있습니다 기존 근로자를 파괴하지 않고xs
토마스 Petricek

29

또한 다음과 같은 경우를 선호합니다 seq.

  • 모든 요소를 ​​동시에 메모리에 저장하고 싶지는 않습니다.

  • 성능은 중요하지 않습니다.

  • 열거 전후에 무언가를해야합니다. 예를 들어 데이터베이스에 연결하고 연결을 닫습니다.

  • 연결하지 않습니다 (반복 Seq.append하면 스택 오버플로가 발생합니다).

선호하는 list경우 :

  • 요소가 거의 없습니다.

  • 당신은 많은 것을 준비하고 참수 할 것입니다.

어느 쪽 seq도 아니다은 list병렬 처리에 대한 좋은하지 않습니다하지만 반드시 그들 중 나쁜 의미하지 않는다. 예를 들어, 둘 중 하나를 사용하여 병렬로 수행 할 개별 작업 항목의 작은 무리를 나타낼 수 있습니다.


"seq도 list도 병렬 처리에 좋지 않습니다.": seq가 병렬 처리에 좋지 않은 이유를 확장 할 수 있습니까? 그렇다면 병렬 처리에 좋은 점은 무엇입니까?
Asik

5
@Dr_Asik 배열은 재귀 적으로 세분화하고 좋은 참조 위치를 유지할 수 있기 때문에 가장 좋습니다. 나무도 세분화 할 수 있기 때문에 차선책이되지만 참조의 위치는 그다지 좋지 않습니다. 목록과 시퀀스는 세분화 할 수 없기 때문에 좋지 않습니다. 대체 요소를 파밍하면 가능한 최악의 참조 위치를 얻을 수 있습니다. Guy Steele은 지역성 ( 캐시 복잡성 이라고도 함)이 아닌 작업과 깊이 만 고려하지만 병렬성을 방해하는 선형 컬렉션에 대해 논의했습니다 . labs.oracle.com/projects/plrg/Publications/…
JD

12

한 가지 작은 점 : Seq그리고 병렬 처리 Array보다 낫습니다 List.

당신은 몇 가지 옵션이 있습니다 : PSeq를 F # 파워팩에서 Array.Parallel의 모듈과 Async.Parallel (비동기 계산). 목록은 순차 특성 ( head::tail구성) 으로 인해 병렬 실행에 끔찍합니다 .


좋은 점입니다. 제가 염두에 둔 시나리오는 한 스레드에서 컬렉션을 빌드하고 (즉, 일부 서비스에서 값을받을 때) 다른 스레드에서 컬렉션을 사용해야하는 경우 (예 : 통계를 계산하고 표시하기 위해)였습니다. 나는 병렬 처리 (이미 모든 데이터가 메모리에있을 때)에 대해 Array또는 PSeq훨씬 더 나은 것에 동의합니다 .
Tomas Petricek

1
병렬 처리 seq보다 더 나은 이유는 무엇 list입니까? seq또한 순차적 인 특성으로 인해 병렬 실행이 끔찍합니다 ...
JD

7

목록이 더 기능적이고 수학 친화적입니다. 각 요소가 같으면 2 개의 목록이 같습니다.

순서는 아닙니다.

let list1 =  [1..3]
let list2 =  [1..3]
printfn "equal lists? %b" (list1=list2)

let seq1 = seq {1..3}
let seq2 = seq {1..3}
printfn "equal seqs? %b" (seq1=seq2)

여기에 이미지 설명 입력


5

항상 Seq공개 API에 노출해야합니다 . 내부 구현에서 List및 사용하십시오 Array.


다른 .NET 언어와 잘 작동하기 때문입니까? 즉, a SeqIEnumerable<T>?
dodgy_coder

좋은 디자인 관행 때문입니다. 더 이상 필요한만큼의 정보를 노출하지 마십시오.
Aleš Roubíček

좋습니다. 이것은 C # 코드에서도 좋은 방법입니다.
dodgy_coder

1
변경 가능한 반환 구조 (예 : .NET의이 디자인 결함 : msdn.microsoft.com/en-us/library/afadtey7.aspx ) 또는 다른 .NET 언어에서 사용할 수있는 API 의 컨텍스트에 동의하지만 동의 하지 않습니다. 일반적으로 동의합니다. 부분적으로 seq는 병렬 처리에 좋지 않기 때문 입니다.
JD
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.