【问题标题】:How to find index of a value in an array ignoring index of a specified value如何在忽略指定值的索引的数组中查找值的索引
【发布时间】:2017-06-25 13:47:07
【问题描述】:

是否可以使用 Linq 从数组中查找值的索引而忽略特定值的索引?

例如。 数组 = {1,2,3,4,0,5,0,6,7}

6 的索引是 7 如果我选择忽略全零的索引 而是返回 5 作为 6 的索引 通过从零开始计数,但在数组中保留 0。

【问题讨论】:

  • 出于兴趣,你为什么要那个值?
  • 我并不完全看重这个值。我想要的是在索引中插入一个忽略所有零的值(例如,array[4] = 2 将插入 5 并将其替换为 2。
  • 我想修改一个已更改的数组的副本。
  • “忽略所有零”是什么意思?您想返回一个更新后的数组,其中的值被替换并且没有零?或者只是你想替换一个值?

标签: c# .net vb.net linq


【解决方案1】:

例如,

var x = new[] { 0, 1, 3, 0, 4, 5, 6 };

使用 ToList()

x.Where(i => i != 0).ToList().IndexOf(5);

使用 ToArray()

Array.FindIndex(x.Where(i => i != 0).ToArray(), i => i == 5);

【讨论】:

    【解决方案2】:

    FastReplaceFirstMatch 可能是解决您非常具体的问题的最快选择(在对其他回复之一的评论中提到)。

    我还为您指定的问题(在您的问题中,而不是在注释说明中)添加了一些基于 LINQ 的解决方案(这将比其他基于 ToList 的解决方案快得多)。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace Test
    {
        public static class GenericExtensions
        {
            public static int IndexExcludingValue<T>(this IEnumerable<T> test, T valueToFind, T valueToExclude) where T : struct
            {
                return test.Where(z => !Equals(z, valueToExclude))
                    .Select((value, index) => new { value, index })
                    .FirstOrDefault(z => Equals(z.value, valueToFind))?.index ?? -1;
            }
    
            public static T[] FastReplaceFirstMatch<T>(this T[] test, T valueToFind, T valueToReplace) where T : struct
            {
                var hasBeenReplaced = false;
    
                var index = Array.FindIndex(test, z => Equals(z, valueToFind));
    
                if (index != -1)
                {
                    test[index] = valueToReplace;
                }
    
                return test;
            }
    
    
            public static IEnumerable<T> ReplaceFirstMatch<T>(this IEnumerable<T> test, T valueToFind, T valueToReplace) where T : struct
            {
                var hasBeenReplaced = false;
    
                return test
                    .Select(value =>
                        {
                            if (!hasBeenReplaced && Equals(value, valueToFind))
                            {
                                hasBeenReplaced = true;
                                value = valueToReplace;
                            }
                            return value;
                        });
            }
        }
    
        public class Program
        {
            private static int[] bob = { 1, 2, 3, 4, 0, 5, 0, 6, 7 };
    
            static void Main(string[] args)
            {
                Console.WriteLine(bob.IndexExcludingValue(6, 0));
                Console.WriteLine(string.Join(",", bob.ReplaceFirstMatch(6, 8).ToArray()));
                Console.WriteLine(string.Join(",", bob.FastReplaceFirstMatch(6, 10)));
    
                Console.ReadLine();
            }
        }
    }
    

    【讨论】:

    • 这对@Godon2020 有帮助吗?
    【解决方案3】:

    此刻我能想到的就是用它来忽略数组上的特定元素:

    array.Where(e => e != 0);
    

    然后这个来获取索引:

    array.Where(e => e != 0).ToList().IndexOf(6);
    

    【讨论】:

    • 那么...返回的索引在哪里?
    • @MetaColon 已编辑,我假设他已经知道如何获取索引
    • 抱歉,忘记了 .ToList()。
    【解决方案4】:

    只是添加另一个我认为更简单的解决方案:您可以再次消除零,然后将生成的可枚举转换为列表并在此列表上使用 IndexOf

    array.Where(x => x != 0)
       .ToList().IndexOf(6); //Results in 5 as well
    

    作为另一种我认为更漂亮的解决方案,您可以编写这样的扩展方法:

    public static class Extensions
    {
        public static int IndexOfIgnoring<T> (this IEnumerable<T> collection, T indexOf, T toIgnore) =>
            collection.Where (arg => !Equals (arg, toIgnore)).ToList ().IndexOf (indexOf);
    }
    

    你可以这样使用:

    static void Main (string [] args)
    {
        Console.WriteLine ($"{new [] {1, 2, 3, 4, 0, 5, 0, 6, 7}.IndexOfIgnoring (6, 0)}");
        Console.ReadLine ();
    }
    

    你可以阅读更多关于扩展方法here

    编辑正如 OP 的评论问我的那样,这是一个解决方案,在索引处设置项目,忽略特定项目。

    因此我想再次使用扩展方法:

    public static class Extensions
    {
        public static int IndexOfIgnoring<T> (this IEnumerable<T> collection, T indexOf, T toIgnore) =>
            collection.Where (arg => !Equals (arg, toIgnore)).ToList ().IndexOf (indexOf);
    
        public static int GetRealIndexOfIgnoring<T> (this IEnumerable<T> collection, int indexIgnored, T toIgnore)
            => collection.Select ((t, i) => new Tuple<T, int> (t, i)).Where (arg => !Equals (arg.Item1, toIgnore)).
                          ToList () [indexIgnored].Item2;
    
        public static IEnumerable<T> SetAtIndexOfIgnoring<T> (this IEnumerable<T> collection, int indexIgnored, T toIgnore, T toSet)
        {
            var enumerable = collection as IList<T> ?? collection.ToList ();
            return enumerable.Select ((t, i) => i == GetRealIndexOfIgnoring (enumerable, indexIgnored, toIgnore) ? toSet : t);
        }
    }
    

    我们可以这样使用:

    static void Main (string [] args)
    {
        var collection = new [] {1, 2, 3, 4, 0, 5, 0, 6, 7};
        var ignoredIndex = collection.IndexOfIgnoring (6, 0);
        Console.WriteLine ($"{ignoredIndex}");
        collection = collection.SetAtIndexOfIgnoring(ignoredIndex, 0, 10).ToArray();
        Console.WriteLine(string.Join(", ", collection));
        Console.ReadLine ();
    }
    

    哪些输出:

    5
    1, 2, 3, 4, 0, 5, 0, 10, 7
    

    【讨论】:

    • 如果我想在索引中插入一个值(例如,array[4] = 2 将插入 5 并将其替换为 2。
    • @Godon2020 我不太确定我是否理解你的意思,但我想你只需要重新执行它。
    • 我的意思是在忽略所有零之后从索引中获取值,我如何插入索引也忽略所有零索引。因此(例如,array[4] = 2 将插入并用 2 替换 5,而不是用 2 替换 0)
    • @mjwills 取决于你期望它做什么。
    • @mjwills 它是可区分的,因为集合的计数不是它的有效索引(最大有效索引为 count - 1)
    猜你喜欢
    • 2020-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多