it-swarm.com.de

Wie kann ich jedes nte Element aus einer Liste <T> erhalten?

Ich verwende .NET 3.5 und möchte jedes * n * -te Element aus einer Liste erhalten. Es ist mir egal, ob dies mit einem Lambda-Ausdruck oder LINQ erreicht wird.

Bearbeiten

Sieht so aus, als hätte diese Frage eine Menge Debatten ausgelöst (was eine gute Sache ist, richtig?). Die Hauptsache, die ich gelernt habe, ist, dass Sie, wenn Sie glauben, dass Sie alle Möglichkeiten kennen, etwas zu tun (auch so einfach wie das), erneut nachdenken!

97
Paul Suart
return list.Where((x, i) => i % nStep == 0);
169
mquander

Ich weiß, dass es "old school" ist, aber warum nicht einfach eine for-Schleife mit Stepping = n verwenden?

36
Michael Todd

Hört sich an wie

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

würde den Trick tun. Ich sehe keine Notwendigkeit, Linq oder einen Lambda-Ausdruck zu verwenden.

BEARBEITEN:

Mach es 

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];
  }
}

und Sie schreiben auf LINQische Weise

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

2. Edit :

Um es noch mehr LINQish zu machen

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

Sie können die Where-Überladung verwenden, die den Index zusammen mit dem Element übergibt

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

Für Schleife 

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

Ich bin nicht sicher, ob ein LINQ-Ausdruck möglich ist, aber ich weiß, dass Sie die Erweiterungsmethode Where verwenden können. Zum Beispiel, um jeden fünften Artikel zu erhalten:

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

Dies wird den ersten Artikel und jeden fünften von dort erhalten. Wenn Sie beim fünften Element anstelle des ersten beginnen möchten, vergleichen Sie mit 4 und nicht mit 0.

3
Guffa

Ich denke, wenn Sie eine linq-Erweiterung bereitstellen, sollten Sie in der Lage sein, auf der am wenigsten spezifischen Schnittstelle, also auf IEnumerable, zu arbeiten. Wenn Sie die Geschwindigkeit besonders für große N wollen, können Sie den indizierten Zugriff natürlich überladen. Letzteres macht die Iteration über große Mengen nicht benötigter Daten überflüssig und ist viel schneller als die Where-Klausel. Durch die Bereitstellung beider Überladungen kann der Compiler die am besten geeignete Variante auswählen.

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];
    }
}
2
belucha

Imho ist keine Antwort richtig. Alle Lösungen beginnen bei 0. Aber ich möchte das echte n-te Element haben

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
user2340145
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();
}

ausgabe

 enter image description here

0
Anwar Ul Haq

@belucha Das gefällt mir, weil der Client-Code sehr gut lesbar ist und der Compiler die effizienteste Implementierung auswählt. Darauf würde ich aufbauen, indem ich die Anforderungen auf IReadOnlyList<T> reduziere und die Division für Hochleistungs-LINQ speichere:

    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];
        }
    }
0
Spoc