【问题标题】:Get List<> element position in c# using LINQ使用 LINQ 在 c# 中获取 List<> 元素位置
【发布时间】:2009-07-10 17:12:53
【问题描述】:

我有一个带有数字的列表, 我想使用 LINQ 找到最小值(不是值)的位置

例子:

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

现在我正在寻找一个返回我的函数

输出 = 2

因为最小值在列表中的第 2 位。

【问题讨论】:

  • 这些值总是不同的吗?
  • 不,值不是唯一的
  • 嗯,如果值不是唯一的,那么我想可能想要找到多个位置。或者遇到的第一个最小值的位置。
  • 如果您想要一个唯一值的集合,那么您应该考虑使用继承自ISet<T> 的集合类:即HashSet<T>SortedSet<T>

标签: c# .net linq .net-core position


【解决方案1】:
var list = new List<int> { 3, 1, 0, 5 };
int pos = list.IndexOf(list.Min()); // returns 2

【讨论】:

  • 如果列表中有另一个项目也是 0 会怎样?我不是批评,我只是想知道。
  • 是否列出通用对象以跟踪其中的最小值?
  • @mgroves - 它返回最小值的第一个索引
  • 我认为IndexOf返回指定参数的第一个索引,如果没有找到则返回-1。
  • (IndexOf) 搜索指定对象并返回整个 List)>) 中第一次出现的从零开始的索引。 msdn.microsoft.com/en-us/library/e4w08k17.aspx
【解决方案2】:

当您特别要求 LINQ 解决方案时,您得到的只是非 LINQ 解决方案,这里有一个 LINQ 解决方案:

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;

但这并不意味着 LINQ 是解决此问题的最佳解决方案...

编辑:

如果代码稍微复杂一点,效果会更好:

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

要获得最佳性能,您可以使用普通循环遍历项目,同时跟踪最低的项目:

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

【讨论】:

  • 技术上是其他人添加了 LINQ 要求
  • 实际上,原来的发帖人似乎将其标记为 LINQ,但在帖子中没有提及 LINQ。
  • 为什么投反对票?如果你不解释你认为错误的地方,它就无法改进答案。
  • @JulienGuertault:您对如何使用 LINQ 有更好的建议吗?
  • @JulienGuertault:公平点。我添加了一个性能更好的替代方案。现在去投票接受的答案,它需要做更多的工作......;)
【解决方案3】:

获得职位的最佳方式是FindIndex 此功能仅适用于 List

例子

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

如果你有枚举器或数组使用这种方式

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

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

【讨论】:

    【解决方案4】:

    我同意 LINQ 不是解决这个问题的最佳方案,但这里有另一个变体,即 O(n)。它不排序,只遍历列表一次。

    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
    

    【讨论】:

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

      【讨论】:

        【解决方案6】:

        一个列表可以包含多个等于最小值的元素(见下文)。

        我编写的通用扩展方法.FindEveryIndex() 可以处理整数、字符串等,而且非常灵活,因为您可以将条件指定为 Lambda 表达式。

        另一个优点是它返回一个包含所有匹配条件的索引的列表,而不仅仅是第一个元素。

        关于您的问题:最小值可以返回为:

        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
        

        它将返回索引 0、2 和 5,因为 lst1 中的最小值是 1

        输出:0,2,5

        示例 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]
        }
        

        扩展类:

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

        注意:将两段代码 sn-ps 复制到 LinqPad C# 程序中即可立即运行。

        或者,使用DotNetFiddle在线运行它。

        【讨论】:

          【解决方案7】:
          List<int> data = new List<int>();
          data.AddRange(new[] { 3, 1, 0, 5 });
          Console.WriteLine(data.IndexOf(data.Min()));
          

          【讨论】:

            【解决方案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);
            

            【讨论】:

              【解决方案9】:

              我不一定推荐这种 CPS 风格的代码,但它可以工作并且是 O(n),这与使用 OrderBy 的解决方案不同:

              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;
              

              如果您想要最后一个最小副本,而不是第一个,请将 > 更改为 >=。

              使用 .minv 获取最小值或两者都不使用获取包含索引和最小值的 2 元组。

              我等不及 .NET 在 4.0 中获取元组。

              【讨论】:

                【解决方案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;
                }
                

                【讨论】:

                • 我认为这个答案很幽默:)
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2012-10-04
                • 2015-07-14
                • 1970-01-01
                • 1970-01-01
                • 2012-05-07
                • 2011-02-26
                • 2013-01-22
                相关资源
                最近更新 更多