Lijst ophalen<> elementpositie in c# met LINQ

Ik heb een lijst met nummers,
en ik zou graag de positie van het minimum (geen waarde) willen vinden met LINQ

Voorbeeld:

var lst = new List<int>() { 3, 1, 0, 5 };

Nu ben ik op zoek naar een functie die mij terugstuurt

uitvoer = 2

omdat het minimum op positie 2 in de lijst staat.


Antwoord 1, autoriteit 100%

var list = new List<int> { 3, 1, 0, 5 };
int pos = list.IndexOf(list.Min()); // returns 2

Antwoord 2, autoriteit 58%

Omdat u specifiek om een ​​LINQ-oplossing vroeg en u alleen niet-LINQ-oplossingen kreeg, is hier een LINQ-oplossing:

List<int> values = new List<int> { 3, 1, 0, 5 };
int index =
   values
   .Select((n, i) => new { Value = n, Index = i })
   .OrderBy(n=>n.Value)
   .First()
   .Index;

Dat betekent echter niet dat LINQ de beste oplossing is voor dit probleem…

Bewerken:

Met een wat complexere code presteert dit iets beter:

int index =
   values
   .Select((n, i) => new { Value = n, Index = i })
   .Aggregate((a,b) => a.Value < b.Value ? a : b)
   .Index;

Om de beste prestaties te krijgen, zou je een gewone lus gebruiken om door de items te gaan, terwijl je de laagste bijhoudt:

int index = 0, value = values[0];
for (int i = 1; i < values.Length; i++) {
  if (values[i] < value) {
    value = values[i];
    index = i;
  }
}

Antwoord 3, autoriteit 16%

De beste manier om de positie te achterhalen is door FindIndex
Deze functie is alleen beschikbaar voor Lijst<>

Voorbeeld

int id = listMyObject.FindIndex(x => x.Id == 15); 

Als je een enumerator of array hebt, gebruik dan deze manier

int id = myEnumerator.ToList().FindIndex(x => x.Id == 15); 

of

  int id = myArray.ToList().FindIndex(x => x.Id == 15); 

Antwoord 4, autoriteit 4%

Ik ben het ermee eens dat LINQ niet de beste oplossing is voor dit probleem, maar hier is nog een variant, namelijk O(n). Het sorteert niet en doorloopt de lijst maar één keer.

var list = new List<int> { 3, 1, 0, 5 };
int pos = Enumerable.Range(0, list.Count)
    .Aggregate((a, b) => (list[a] < list[b]) ? a : b); // returns 2

Antwoord 5, autoriteit 2%

var data = new List<int> { 3, 1, 0, 5 };
var result = Enumerable.Range(0, data.Count).OrderBy(n => data[n]).First();

Antwoord 6

Een lijst kan meerdere elementen bevatten die gelijk zijn aan de minimumwaarde (zie hieronder).

De generieke extensiemethode .FindEveryIndex()die ik schreef, werkt met gehele getallen, strings, … en is vrij flexibel omdat je je voorwaarde kunt specificeren als Lambda-expressie.

Een ander voordeel is dat het een lijst retourneert van alle indices die aan de voorwaarde voldoen, niet alleen het eerste element.

Wat betreft uw vraag:het minimum kan worden geretourneerd als:

var lst = new List<int>() { 1, 2, 1, 3, 4, 1 };  // example list
var minimum = lst.Min();  // get the minumum value of lst
var idx = lst.FindEveryIndex(x => x == minimum);  // finds all indices matching condition
Console.WriteLine($"Output: {String.Join(',', idx.ToArray())}");  // show list of indices

Het geeft de indices 0, 2 en 5 terug, omdat het minimum in lst11is:

Uitgang: 0,2,5

Voorbeeld 2:

void Main()
{   
    // working with list of integers
    var lst1 = new List<int>() { 1, 2, 1, 3, 4, 1 };
    lst1.FindEveryIndex(x => x==1).Dump("Find 1");   // finds indices: [0, 2, 5]
    lst1.FindEveryIndex(x => x==2).Dump("Find 2");   // finds index: [1]
    lst1.FindEveryIndex(x => x==9).Dump("Find 9");   // returns [-1]
    // working with list of strings
    var lst2 = new List<string>() { "A", "B", "A", "C", "D", "A"};
    lst2.FindEveryIndex(x => x=="A").Dump("Find A");   // finds indices: [0, 2, 5]
    lst2.FindEveryIndex(x => x=="B").Dump("Find B");   // finds index: [1]
    lst2.FindEveryIndex(x => x=="X").Dump("Find X");   // returns [-1]
}

Extension Class:

public static class Extension
{
    // using System.Collections.Generic;
    public static IEnumerable<int> FindEveryIndex<T>(this IEnumerable<T> items, 
                                                     Predicate<T> predicate)
    {
        int index = 0; bool found = false;
        foreach (var item in items)
        {
            if (predicate(item))
            {
                found = true; yield return index;
            };
            index++;
        }
        if (!found) yield return -1;
    }
}

Opmerking: Kopieer de twee codefragmenten in een Linqpad C # -programma en het werkt onmiddellijk.

Of, voer het online uit met dotnetfiddle .


Antwoord 7

List<int> data = new List<int>();
data.AddRange(new[] { 3, 1, 0, 5 });
Console.WriteLine(data.IndexOf(data.Min()));

Antwoord 8

int min = 0;
bool minIsSet = false;
var result = ints
  .Select( (x, i) => new {x, i}
  .OrderBy(z => z.x)
  .Select(z => 
  {
    if (!minIsSet)
    {
      min = z.x;
      minIsSet = true;
    }
    return z;
  }
  .TakeWhile(z => z.x == min)
  .Select(z => z.i);

Antwoord 9

Ik raad deze CPS-style-code niet noodzakelijk aan, maar het werkt en is O (n), in tegenstelling tot de oplossingen die Orderby gebruiken:

var minIndex = list.Aggregate(
    new { i = 0, mini = -1, minv = int.MaxValue },
    (min, x) => (min.minv > x)
        ? new { i = min.i + 1, mini = min.i, minv = x }
        : new { i = min.i + 1, mini = min.mini, minv = min.minv })
    .mini;

Wijzigen & GT; naar & GT; = Als u het laatste minimale dubbele duplicaat wilt, niet de eerste.

Gebruik .minv om de minimumwaarde te krijgen of niet om een ​​2-tuple te krijgen met zowel de index als de minimumwaarde.

Ik kan niet wachten op .NET om tuples in 4.0 te krijgen.


Antwoord 10

List<int>.Enumerator e = l.GetEnumerator();
int p = 0, min = int.MaxValue, pos = -1;
while (e.MoveNext())
{
    if (e.Current < min)
    {
        min = e.Current;
        pos = p;
    }
    ++p;
}

Other episodes