【问题标题】:Select indexes of all elements in sequence依次选择所有元素的索引
【发布时间】:2013-05-01 19:45:50
【问题描述】:

使用 LINQ,我可以编写一个返回项目索引的 IEnumerable 的语句吗?

非常简单的例子:

{1,2,4,5,3}

会回来

{0,1,2,3,4}

{1,2,4,5,3}.Where(num => num == 4)

会回来

{2}

这不是确切的代码,但它应该能够传达这个想法。

【问题讨论】:

  • 如果集合是 IEnumerable 的,它不会是有效的。必须复制到数组或列表中。
  • 你真的问过这个问题吗?任何 Linq 文档都包含许多类似的示例。
  • 另外,您必须知道您正在处理的数组的范围,或者拥有已排序数组的副本,同时还要拥有未排序的数组来检查其索引。
  • @I4V,请发个链接。

标签: c# linq select indexing


【解决方案1】:
var a = new[] {1, 2, 4, 5, 3};

//** First, generates a simple sequence with {0,1,2,3,4} 
//** using the 2 parameter lambda select

var sequence1 = a.Select((_, index) => index);

//** Second, gets an array with all indexes where the value is 4.

// We need both value and index for the next line to work.
var sequence2 = a.Select((value, index) => new {value, index});

// Get all indexes where the value is 4
var indexArray = sequence2.Where(x => x.value == 4)
                          .Select(x => x.index).ToArray();

【讨论】:

  • @Ric 抱歉,我意识到我的回答有点混乱,第一部分只是显示您可以选择索引以获取{0,1,2,3,4},如问题所述,第二个序列以及@987654323 @ 解决了问题也要求的“选择值为 x 的索引”。当然,如果值重复,您需要使用ToArray() 而不是FirstOrDefault() 来获取所有值。
【解决方案2】:
var numbers = Enumerable.Range(1,10).ToList();

int index = -1;

var indices = numbers.Select(x => i++).ToList();

【讨论】:

    【解决方案3】:

    如果您愿意稍微更改语法并使用扩展方法,则以下内容将起作用。我不喜欢它,因为它会为每次调用创建一个新序列。

    var sequence = new[] { 1, 2, 4, 5, 3 };
    
    sequence.Indexer().Select(num => num.Item1); // returns {0,1,2,3,4}
    sequence.Indexer().Where(num => num.Item2 == 4).Select(num => num.Item1); // returns {2}
    
    private static IEnumerable<Tuple<int, T>> Indexer<T>(this IEnumerable<T> sequence)
    {
        return sequence.Select((x, y) => new Tuple<int, T>(y, x));
    }
    

    更好的方法是完全改变你的写作方式:

    var sequence = new[] { 1, 2, 4, 5, 3 };
    
    sequence.Select((num, index) => new { Num = num, Index = index }).Select(num => num.Index); // returns {0, 1,2,3,4}
    sequence.Select((num, index) => new { Num = num, Index = index }).Where(num => num.Num == 4).Select(num => num.Index); // returns {2}
    

    【讨论】:

      【解决方案4】:

      完整的索引集仅取决于项目的数量,而不是值,因此您可以这样做:

      IEnumerable<int> indices = Enumerable.Range(0, 5);
      

      如果您正在处理IEnumerable&lt;T&gt;,您可以执行以下操作来获取匹配 4 的项目的索引:

      IEnumerable<int> values = new[] { 1, 2, 3, 4, 5 };
      int indexOf4 = (
          values.Select((v, i) => new {v, i})
                .FirstOrDefault(vi => vi.v == 4) ?? new {v = 0, i = -1}).i;
      

      这处理了值源不包含匹配项(返回-1)的情况。

      当然,如果您不介意将您的 IEnumerable&lt;T&gt; 转换为列表,那么您可以致电 IndexOf

      int indexOf4a = values.ToList().IndexOf(4);
      

      但是,我怀疑这个问题真正要寻找的方法是找到与特定谓词匹配的值的所有索引。例如:

      IEnumerable<int> big = values.Select((v, i) => new {v, i})
                                   .Where(vi => vi.v > 3)
                                   .Select (vi => vi.i);
      

      返回值的索引&gt; 3:[3, 4]

      如果谓词不匹配任何值,那么您将得到一个空的可枚举结果。

      【讨论】:

        【解决方案5】:
        IEnumerable<int> seq = new[] { 1, 2, 4, 5, 3 };
        
        // The indexes of all elements.
        var indexes = Enumerable.Range(0, seq.Count());
        
        // The index of the left-most element with value 4.
        // NOTE: Will return seq.Count() if the element doesn't exist.
        var index = seq.TakeWhile(x => x != 4).Count();
        
        // The indexes of all the elements with value 4.
        // NOTE: Be careful to enumerate only once.
        int current_index = 0;
        var all_indexes =
            from e in (
                from x in seq
                select new { x, Index = current_index++ }
            )
            where e.x == 4
            select e.Index;
        

        【讨论】:

          【解决方案6】:

          你可以这样做:

          public static IEnumerable<int> WhereIndices<T>(this IEnumerable<T> source, Func<T, bool> predicate)
          {
              return source.Select(Tuple.Create<T, int>)
                  .Where(z => predicate(z.Item1)).Select(z => z.Item2);
          }
          

          它是一个扩展方法,所以把它放在一个静态的非嵌套类中。像使用Where一样使用它,即:

          .WhereIndices(num => num == 4)
          

          【讨论】:

            【解决方案7】:

            应该这样做。不知道它的效率如何..

            List<int> list = new List<int>()
            {
                1,
                2,
                3,
                4,
                5
            };
            
            var indexes = list.Select(item => list.IndexOf(item));
            
            var index = list.Where(item => item == 4).Select(item => list.IndexOf(item));
            

            【讨论】:

            • 你似乎是唯一真正理解这个问题的人。顺便说一句,你可以简称Select(list.IndexOf)
            • -1 list.Select(item =&gt; list.IndexOf(item)); 我想不出更糟的办法了。
            • O(n^2),所以根本没有效率,因为问题是线性的。
            猜你喜欢
            • 2013-10-08
            • 2015-05-07
            • 1970-01-01
            • 2017-05-20
            • 2012-09-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多