List <T>에서 모든 n 번째 항목을 어떻게 가져올 수 있습니까?


114

.NET 3.5를 사용 n하고 있으며 목록에서 * * 번째 항목을 모두 얻을 수 있기를 원합니다 . 람다 식을 사용했는지 LINQ를 사용했는지에 대해서는 신경 쓰지 않습니다.

편집하다

이 질문이 꽤 많은 논쟁을 불러 일으켰던 것 같습니다 (좋은 일 이죠?). 내가 배운 가장 중요한 것은 무언가를하는 모든 방법을 알고 있다고 생각할 때 (이것처럼 간단하더라도) 다시 생각한다는 것입니다!


나는 당신의 원래 질문 뒤에있는 어떤 의미도 편집하지 않았습니다. 나는 그것을 정리하고 대문자와 구두점을 올바르게 사용했습니다. (.NET은 대문자로 표시되고 LINQ는 모두 대문자로되어 있으며 '람다'가 아니라 '람다 식'입니다.)
George Stocker

1
"fussed"를 전혀 동의어가 아닌 "sure"로 대체했습니다.
mqp

그렇게 보일 것입니다. "사용할 수 있는지 잘 모르겠습니다 ..."가 아니라면 확실히하는 것도 말이되지 않습니다.
Samuel

예, 제가 이해하는대로 그게 맞습니다.
mqp

fussed를 "concerned"로 바꾸면 "람다 식을 사용했는지 LINQ를 사용했는지에 대해서는 관심이 없습니다."라고 표시되는 것이 가장 좋습니다.
TheTXI

답변:


189
return list.Where((x, i) => i % nStep == 0);

5
@mquander : 실제로 n 번째-1 요소를 제공합니다. 실제 n 번째 요소를 원하면 (첫 번째 요소를 건너 뛰고) i에 1을 더해야합니다.
casperOne

2
예, "nth"가 의미하는 바에 따라 다소 차이가 있다고 생각하지만 귀하의 해석이 더 일반적 일 수 있습니다. 필요에 맞게 i에서 더하거나 빼십시오.
mqp

5
참고 : Linq / Lambda 솔루션은 고정 증분을 사용하는 단순 루프보다 성능이 훨씬 떨어집니다.
MartinStettner

5
반드시 지연된 실행을 사용하면 foreach 루프에서 사용할 수 있으며 원래 목록을 한 번만 루프합니다.
Samuel

1
"실용적"이라는 의미에 따라 다릅니다. 사용자가 버튼을 클릭 할 때 30 개 항목의 목록에있는 다른 모든 항목을 빠르게 가져 오는 방법이 필요하다면이 방법이 실용적이라고 말하고 싶습니다. 때때로 성능은 더 이상 중요하지 않습니다. 물론 때로는 그렇습니다.
mqp

37

나는 그것이 "오래된 학교"라는 것을 알고 있지만, 왜 stepping = n과 함께 for 루프를 사용하지 않는가?


그것은 기본적으로 제 생각이었습니다.
Mark Pim

1
@Michael Todd : 작동하지만 문제는 모든 곳에서 해당 기능을 복제해야한다는 것입니다. LINQ를 사용하면 작성된 쿼리의 일부가됩니다.
casperOne

8
@casperOne : 저는 프로그래머가 이것을 처리하기 위해 서브 루틴이라는 것을 발명했다고 믿습니다;) 실제 프로그램에서는 영리한 LINQ 버전에도 불구하고 아마도 루프를 사용할 것입니다. 루프는 모든 요소를 ​​반복 할 필요가 없음을 의미하기 때문입니다 ( 인덱스를 N 씩 증가시킵니다.)
mqp

나는 구식 솔루션을 선택하는 데 동의하며 이것이 더 잘 수행 될 것이라고 생각합니다.
Jesper Fyhr Knudsen

멋진 새 구문으로 쉽게 빠져들 수 있습니다. 그래도 그 재미.
Ronnie

34

처럼 들린다

IEnumerator<T> GetNth<T>(List<T> list, int n) {
  for (int i=0; i<list.Count; i+=n)
    yield return list[i]
}

트릭을 할 것입니다. Linq 또는 람다 식을 사용할 필요가 없다고 생각합니다.

편집하다:

그것을 만드십시오

public static class MyListExtensions {
  public static IEnumerable<T> GetNth<T>(this List<T> list, int n) {
    for (int i=0; i<list.Count; i+=n)
      yield return list[i];
  }
}

LINQish 방식으로 작성합니다.

from var element in MyList.GetNth(10) select element;

2 차 편집 :

더 LINQish로 만들기 위해

from var i in Range(0, ((myList.Length-1)/n)+1) select list[n*i];

2
IEnumerable의 모든 요소를 ​​본질적으로 반복하는 Where () 메서드 대신 this [] getter를 사용하는이 메서드를 좋아합니다. IList / ICollection 유형이있는 경우 이것이 더 나은 방법 인 IMHO입니다.
spoulson

목록이 어떻게 작동하는지 확실하지 않지만 루프를 사용하고 list[i]대신 반환하는 이유는 list[n-1]무엇입니까?
Juan Carlos Oropeza

@JuanCarlosOropeza는 목록의 n 번째 요소뿐만 아니라 모든 n 번째 요소 (예 : 0, 3, 6 ...)를 반환합니다.
alfoks

27

요소와 함께 인덱스를 전달하는 Where 오버로드를 사용할 수 있습니다.

var everyFourth = list.Where((x,i) => i % 4 == 0);

1
내가이 방법의 팬이라고 말해야한다.
Quintin Robinson

1
나는 당신이 그렇게 할 수 있다는 것을 계속 잊고 있습니다 – 아주 좋습니다.
Stephen Newman

10

For 루프

for(int i = 0; i < list.Count; i += n)
    //Nth Item..

Count는 열거 형을 평가합니다. 이것이 linq 친화적 인 방식으로 수행 되었다면 느리게 평가하고 처음 100 개의 값을 취할 수 있습니다. 요소를 평가하는
RhysC

1
@RhysC 일반적으로 열거 형에 대한 좋은 지적입니다. OTOH, 질문이 지정 List<T>했으므로 Count저렴하다고 정의됩니다.
ToolmakerSteve 2019

3

LINQ 식으로 할 수 있는지 확실하지 않지만 Where확장 메서드를 사용하여 수행 할 수 있다는 것을 알고 있습니다 . 예를 들어 모든 다섯 번째 항목을 얻으려면 :

List<T> list = originalList.Where((t,i) => (i % 5) == 0).ToList();

이것은 거기에서 첫 번째 항목과 매 다섯 번째 항목을 가져옵니다. 첫 번째 항목이 아닌 다섯 번째 항목에서 시작하려면 0과 비교하는 대신 4와 비교합니다.


3

linq 확장을 제공하면 최소한의 특정 인터페이스, 따라서 IEnumerable에서 작업 할 수 있어야한다고 생각합니다. 물론, 특히 큰 N에 대해 속도를 내고 있다면 인덱스 액세스에 과부하를 제공 할 수 있습니다. 후자는 필요하지 않은 많은 양의 데이터를 반복 할 필요가 없으며 Where 절보다 훨씬 빠릅니다. 두 오버로드를 모두 제공하면 컴파일러가 가장 적합한 변형을 선택할 수 있습니다.

public static class LinqExtensions
{
    public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n)
    {
        if (n < 0)
            throw new ArgumentOutOfRangeException("n");
        if (n > 0)
        {
            int c = 0;
            foreach (var e in list)
            {
                if (c % n == 0)
                    yield return e;
                c++;
            }
        }
    }
    public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
    {
        if (n < 0)
            throw new ArgumentOutOfRangeException("n");
        if (n > 0)
            for (int c = 0; c < list.Count; c += n)
                yield return list[c];
    }
}

이것은 모든 목록에서 작동합니까? 사용자 지정 클래스에 대한 목록에서 사용하려고 시도하고 <class> 대신 IEnumarted <class>를 반환하고 coversion (class) List.GetNth (1)을 강제 실행하지 않기 때문입니다.
Juan Carlos Oropeza

내 잘못이 GetNth (1) .FirstOrDefault ();
Juan Carlos Oropeza

0
private static readonly string[] sequence = "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15".Split(',');

static void Main(string[] args)
{
    var every4thElement = sequence
      .Where((p, index) => index % 4 == 0);

    foreach (string p in every4thElement)
    {
        Console.WriteLine("{0}", p);
    }

    Console.ReadKey();
}

산출

여기에 이미지 설명 입력


0

Imho 대답이 옳지 않습니다. 모든 솔루션은 0부터 시작합니다.하지만 실제 n 번째 요소를 갖고 싶습니다.

public static IEnumerable<T> GetNth<T>(this IList<T> list, int n)
{
    for (int i = n - 1; i < list.Count; i += n)
        yield return list[i];
}

0

@belucha 나는 클라이언트 코드가 매우 읽기 쉽고 컴파일러가 가장 효율적인 구현을 선택하기 때문에 이것을 좋아합니다. IReadOnlyList<T>고성능 LINQ에 대한 요구 사항을 줄이고 부서를 저장하여이를 기반으로합니다.

    public static IEnumerable<T> GetNth<T>(this IEnumerable<T> list, int n) {
        if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
        int i = n;
        foreach (var e in list) {
            if (++i < n) { //save Division
                continue;
            }
            i = 0;
            yield return e;
        }
    }

    public static IEnumerable<T> GetNth<T>(this IReadOnlyList<T> list, int n
        , int offset = 0) { //use IReadOnlyList<T>
        if (n <= 0) throw new ArgumentOutOfRangeException(nameof(n), n, null);
        for (var i = offset; i < list.Count; i += n) {
            yield return list[i];
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.