목록이 아닌 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 Seq는 IEnumerable<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.