cod*_*nix 306 .net c# linq c#-3.0
给定像这样的数据源:
var c = new Car[]
{
new Car{ Color="Blue", Price=28000},
new Car{ Color="Red", Price=54000},
new Car{ Color="Pink", Price=9999},
// ..
};
Run Code Online (Sandbox Code Playgroud)
如何用LINQ 找到满足一定条件的第一辆车的索引?
编辑:
我可以想到这样的东西,但它看起来很糟糕:
int firstItem = someItems.Select((item, index) => new
{
ItemName = item.Color,
Position = index
}).Where(i => i.ItemName == "purple")
.First()
.Position;
Run Code Online (Sandbox Code Playgroud)
用一个普通的循环解决这个问题会是最好的吗?
Yur*_*ich 670
myCars.Select((v, i) => new {car = v, index = i}).First(myCondition).index;
Run Code Online (Sandbox Code Playgroud)
或稍短
myCars.Select((car, index) => new {car, index}).First(myCondition).index;
Run Code Online (Sandbox Code Playgroud)
Red*_*wan 135
简单地说:
int index = List.FindIndex(your condition);
Run Code Online (Sandbox Code Playgroud)
例如
int index = cars.FindIndex(c => c.ID == 150);
Run Code Online (Sandbox Code Playgroud)
SLa*_*aks 124
An IEnumerable不是有序集.
虽然大多数IEnumerables是有序的,但有些(例如Dictionary或HashSet)不是.
因此,LINQ没有IndexOf方法.
但是,你可以自己写一个:
///<summary>Finds the index of the first item matching an expression in an enumerable.</summary>
///<param name="items">The enumerable to search.</param>
///<param name="predicate">The expression to test the items against.</param>
///<returns>The index of the first matching item, or -1 if no items match.</returns>
public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate) {
if (items == null) throw new ArgumentNullException("items");
if (predicate == null) throw new ArgumentNullException("predicate");
int retVal = 0;
foreach (var item in items) {
if (predicate(item)) return retVal;
retVal++;
}
return -1;
}
///<summary>Finds the index of the first occurrence of an item in an enumerable.</summary>
///<param name="items">The enumerable to search.</param>
///<param name="item">The item to find.</param>
///<returns>The index of the first matching item, or -1 if the item was not found.</returns>
public static int IndexOf<T>(this IEnumerable<T> items, T item) { return items.FindIndex(i => EqualityComparer<T>.Default.Equals(item, i)); }
Run Code Online (Sandbox Code Playgroud)
Lum*_*mpN 79
myCars.TakeWhile(car => !myCondition(car)).Count();
Run Code Online (Sandbox Code Playgroud)
有用!想一想.第一个匹配项的索引等于它之前的(不匹配)项的数量.
我也不喜欢你在问题中提出的可怕的标准解决方案.就像接受的答案一样,我选择了一个普通的旧循环,尽管稍作修改:
public static int FindIndex<T>(this IEnumerable<T> items, Predicate<T> predicate) {
int index = 0;
foreach (var item in items) {
if (predicate(item)) break;
index++;
}
return index;
}
Run Code Online (Sandbox Code Playgroud)
请注意,它将返回项目数,而不是-1在没有匹配项时.但是现在让我们忽略这个小麻烦.事实上,可怕的标准解决方案在这种情况下崩溃,我考虑返回一个超出界限的索引.
现在发生的事情是ReSharper告诉我Loop可以转换成LINQ表达式.虽然大多数时候该功能会降低可读性,但这次结果令人敬畏.所以感谢JetBrains.
new匿名对象因此我认为它在时间和空间上是最佳的,同时保持可读性.
-1没有匹配时不返回当然,您始终可以将其隐藏在扩展方法后面.当没有匹配时,最好的做法取决于上下文.
Mar*_*zco 12
我会在这里做出贡献......为什么?只是因为:p它是一个基于Any LINQ扩展和委托的不同实现.这里是:
public static class Extensions
{
public static int IndexOf<T>(
this IEnumerable<T> list,
Predicate<T> condition) {
int i = -1;
return list.Any(x => { i++; return condition(x); }) ? i : -1;
}
}
void Main()
{
TestGetsFirstItem();
TestGetsLastItem();
TestGetsMinusOneOnNotFound();
TestGetsMiddleItem();
TestGetsMinusOneOnEmptyList();
}
void TestGetsFirstItem()
{
// Arrange
var list = new string[] { "a", "b", "c", "d" };
// Act
int index = list.IndexOf(item => item.Equals("a"));
// Assert
if(index != 0)
{
throw new Exception("Index should be 0 but is: " + index);
}
"Test Successful".Dump();
}
void TestGetsLastItem()
{
// Arrange
var list = new string[] { "a", "b", "c", "d" };
// Act
int index = list.IndexOf(item => item.Equals("d"));
// Assert
if(index != 3)
{
throw new Exception("Index should be 3 but is: " + index);
}
"Test Successful".Dump();
}
void TestGetsMinusOneOnNotFound()
{
// Arrange
var list = new string[] { "a", "b", "c", "d" };
// Act
int index = list.IndexOf(item => item.Equals("e"));
// Assert
if(index != -1)
{
throw new Exception("Index should be -1 but is: " + index);
}
"Test Successful".Dump();
}
void TestGetsMinusOneOnEmptyList()
{
// Arrange
var list = new string[] { };
// Act
int index = list.IndexOf(item => item.Equals("e"));
// Assert
if(index != -1)
{
throw new Exception("Index should be -1 but is: " + index);
}
"Test Successful".Dump();
}
void TestGetsMiddleItem()
{
// Arrange
var list = new string[] { "a", "b", "c", "d", "e" };
// Act
int index = list.IndexOf(item => item.Equals("c"));
// Assert
if(index != 2)
{
throw new Exception("Index should be 2 but is: " + index);
}
"Test Successful".Dump();
}
Run Code Online (Sandbox Code Playgroud)
这是我刚刚放在一起的一个小扩展。
public static class PositionsExtension
{
public static Int32 Position<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
return Positions<TSource>(source, predicate).FirstOrDefault();
}
public static IEnumerable<Int32> Positions<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
if (typeof(TSource) is IDictionary)
{
throw new Exception("Dictionaries aren't supported");
}
if (source == null)
{
throw new ArgumentOutOfRangeException("source is null");
}
if (predicate == null)
{
throw new ArgumentOutOfRangeException("predicate is null");
}
var found = source.Where(predicate).First();
var query = source.Select((item, index) => new
{
Found = ReferenceEquals(item, found),
Index = index
}).Where( it => it.Found).Select( it => it.Index);
return query;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以这样称呼它。
IEnumerable<Int32> indicesWhereConditionIsMet =
ListItems.Positions(item => item == this);
Int32 firstWelcomeMessage ListItems.Position(msg =>
msg.WelcomeMessage.Contains("Hello"));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
325692 次 |
| 最近记录: |