获取具有特定条件的第 n 个元素的索引
Get index of nth element with specific condition
假设我们有一个 List<int>
,其内容类似于 [0,0,0,0,1,1,1,1,0,0,0,1,2,2,0,0,2,2]
,我们希望获得第 n 个不为零的数字的索引。
例如,GetNthNotZero(3)
应该 return 6.
使用 for 循环会很容易,但我觉得应该有一个 LINQ 来完成它。使用 LINQ 语句可能吗?
没有开箱即用的方法,但您是否考虑过编写自己的扩展方法来提供类似于 LINQ 的方法FindIndex()
?
class Program
{
static void Main(string[] args)
{
var list = new List<int>{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 2, 2, 0, 0, 2, 2 };
var index = list.FindNthIndex(x => x > 0, 3);
}
}
public static class IEnumerableExtensions
{
public static int FindNthIndex<T>(this IEnumerable<T> enumerable, Predicate<T> match, int count)
{
var index = 0;
foreach (var item in enumerable)
{
if (match.Invoke(item))
count--;
if (count == 0)
return index;
index++;
}
return -1;
}
}
实际上你可以用标准的 LINQ 做到这一点,你可以使用:
List<int> sequence = new List<int>{0,0,0,0,1,1,1,1,0,0,0,1,2,2,0,0,2,2};
int index = sequence.Select((x, ix) => (Item:x, Index:ix))
.Where(x => x.Item != 0)
.Skip(2) // you want the 3rd, so skip 2
.Select(x => x.Index)
.DefaultIfEmpty(-1) // if there is no third matching condition you get -1
.First(); // result: 6
这当然是可能的,但 Linq 方法会使它变得更加复杂。这是显式循环要好得多的情况之一。
使用 Linq 引起的两个重大并发症是:
- 处理空序列或没有零的序列。
- 正在合成要使用的索引。
Linq 解决方案可能如下所示(但请注意,使用 Linq 可能有许多不同的可能方法):
using System;
using System.Collections.Generic;
using System.Linq;
public static class Program
{
public static void Main()
{
var ints = new List<int> { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 2, 2, 0, 0, 2, 2 };
Console.WriteLine(IndexOfNthNotZero(ints, 3)); // 6
Console.WriteLine(IndexOfNthNotZero(Enumerable.Repeat(0, 10), 3)); // -1
Console.WriteLine(IndexOfNthNotZero(ints, 100)); // -1
Console.WriteLine(IndexOfNthNotZero(Array.Empty<int>(), 0)); // -1
}
public static int IndexOfNthNotZero(IEnumerable<int> sequence, int n)
{
return sequence
.Select((v, i) => (value:v, index:i)) // Synthesize the value and index.
.Where(item => item.value != 0) // Choose only the non-zero value.
.Skip(n-1) // Skip to the nth value.
.FirstOrDefault((value:0, index:-1)).index; // Handle missing data by supplying a default index of -1.
}
}
请注意,此实现 returns -1
表示未找到合适的值。
将其与简单循环实现进行比较,我想您会同意使用简单循环更好!
public static int IndexOfNthNotZero(IReadOnlyList<int> sequence, int n)
{
for (int i = 0; i < sequence.Count; ++i)
if (sequence[i] != 0 && --n == 0) // If element matches, decrement n and return index if it reaches 0.
return i;
return -1;
}
或者如果您愿意(避免预递减):
public static int IndexOfNthNotZero(IReadOnlyList<int> sequence, int n)
{
for (int i = 0, numberOfMatches = 0; i < sequence.Count; ++i)
{
if (sequence[i] != 0) // If condition matches
if (++numberOfMatches == n) // Increment number of matches, and if it reaches n
return i; // then return the current index
}
return -1;
}
假设我们有一个 List<int>
,其内容类似于 [0,0,0,0,1,1,1,1,0,0,0,1,2,2,0,0,2,2]
,我们希望获得第 n 个不为零的数字的索引。
例如,GetNthNotZero(3)
应该 return 6.
使用 for 循环会很容易,但我觉得应该有一个 LINQ 来完成它。使用 LINQ 语句可能吗?
没有开箱即用的方法,但您是否考虑过编写自己的扩展方法来提供类似于 LINQ 的方法FindIndex()
?
class Program
{
static void Main(string[] args)
{
var list = new List<int>{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 2, 2, 0, 0, 2, 2 };
var index = list.FindNthIndex(x => x > 0, 3);
}
}
public static class IEnumerableExtensions
{
public static int FindNthIndex<T>(this IEnumerable<T> enumerable, Predicate<T> match, int count)
{
var index = 0;
foreach (var item in enumerable)
{
if (match.Invoke(item))
count--;
if (count == 0)
return index;
index++;
}
return -1;
}
}
实际上你可以用标准的 LINQ 做到这一点,你可以使用:
List<int> sequence = new List<int>{0,0,0,0,1,1,1,1,0,0,0,1,2,2,0,0,2,2};
int index = sequence.Select((x, ix) => (Item:x, Index:ix))
.Where(x => x.Item != 0)
.Skip(2) // you want the 3rd, so skip 2
.Select(x => x.Index)
.DefaultIfEmpty(-1) // if there is no third matching condition you get -1
.First(); // result: 6
这当然是可能的,但 Linq 方法会使它变得更加复杂。这是显式循环要好得多的情况之一。
使用 Linq 引起的两个重大并发症是:
- 处理空序列或没有零的序列。
- 正在合成要使用的索引。
Linq 解决方案可能如下所示(但请注意,使用 Linq 可能有许多不同的可能方法):
using System;
using System.Collections.Generic;
using System.Linq;
public static class Program
{
public static void Main()
{
var ints = new List<int> { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 2, 2, 0, 0, 2, 2 };
Console.WriteLine(IndexOfNthNotZero(ints, 3)); // 6
Console.WriteLine(IndexOfNthNotZero(Enumerable.Repeat(0, 10), 3)); // -1
Console.WriteLine(IndexOfNthNotZero(ints, 100)); // -1
Console.WriteLine(IndexOfNthNotZero(Array.Empty<int>(), 0)); // -1
}
public static int IndexOfNthNotZero(IEnumerable<int> sequence, int n)
{
return sequence
.Select((v, i) => (value:v, index:i)) // Synthesize the value and index.
.Where(item => item.value != 0) // Choose only the non-zero value.
.Skip(n-1) // Skip to the nth value.
.FirstOrDefault((value:0, index:-1)).index; // Handle missing data by supplying a default index of -1.
}
}
请注意,此实现 returns -1
表示未找到合适的值。
将其与简单循环实现进行比较,我想您会同意使用简单循环更好!
public static int IndexOfNthNotZero(IReadOnlyList<int> sequence, int n)
{
for (int i = 0; i < sequence.Count; ++i)
if (sequence[i] != 0 && --n == 0) // If element matches, decrement n and return index if it reaches 0.
return i;
return -1;
}
或者如果您愿意(避免预递减):
public static int IndexOfNthNotZero(IReadOnlyList<int> sequence, int n)
{
for (int i = 0, numberOfMatches = 0; i < sequence.Count; ++i)
{
if (sequence[i] != 0) // If condition matches
if (++numberOfMatches == n) // Increment number of matches, and if it reaches n
return i; // then return the current index
}
return -1;
}