LINQ를 사용하여 인덱스를 가져오는 방법은 무엇입니까?
다음과 같은 데이터 소스를 고려할 때:
var c = new Car[]
{
new Car{ Color="Blue", Price=28000},
new Car{ Color="Red", Price=54000},
new Car{ Color="Pink", Price=9999},
// ..
};
LINQ로 특정 조건을 충족하는 첫 번째 차량의 지수를 어떻게 찾을 수 있습니까?
편집:
나는 이런 것을 생각할 수 있었지만 끔찍해 보입니다:
int firstItem = someItems.Select((item, index) => new
{
ItemName = item.Color,
Position = index
}).Where(i => i.ItemName == "purple")
.First()
.Position;
이것을 단순하고 오래된 루프로 해결하는 것이 최선일까요?
myCars.Select((v, i) => new {car = v, index = i}).First(myCondition).index;
또는 약간 짧은 것.
myCars.Select((car, index) => new {car, index}).First(myCondition).index;
또는 조금 더 짧은 것.
myCars.Select((car, index) => (car, index)).First(myCondition).index;
간단히 수행:
int index = List.FindIndex(your condition);
예.
int index = cars.FindIndex(c => c.ID == 150);
안IEnumerable
순서 집합이 아닙니다.
대부분의 IE 숫자는 순서대로 나열되지만 일부는 다음과 같습니다(예: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)); }
myCars.TakeWhile(car => !myCondition(car)).Count();
효과가 있습니다!생각해 보세요.첫 번째 일치 항목의 인덱스는 일치하지 않는 항목의 개수와 같습니다.
이야기 시간
저도 당신의 질문에서 이미 제안한 끔찍한 표준 해결책이 싫어요.받아들여진 대답처럼 나는 약간의 수정을 가했지만 평범하고 오래된 루프를 선택했습니다.
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;
}
대신 항목 수를 반환합니다.-1
적수가 없을 때하지만 지금은 이 사소한 짜증은 무시해요.사실 이 경우에는 끔찍한 표준 솔루션이 충돌하기 때문에 경계를 벗어난 우수한 인덱스를 반환하는 것을 고려하고 있습니다.
ReSharper는 루프가 LINQ 표현으로 변환될 수 있다고 말합니다.대부분의 경우 기능이 가독성을 악화시키지만, 이번에는 놀라운 결과를 얻었습니다.제트 브레인즈에 대한 칭찬입니다.
분석.
장점
- 간결하다.
- 다른 LINQ와 결합 가능
- 피함
new
익명 개체 입력 - 술어가 처음으로 일치할 때까지만 열거형을 평가합니다.
그래서 저는 읽을 수 있는 상태로 시간과 공간에서 최적이라고 생각합니다.
단점
- 처음에는 명확하지 않습니다.
- 반환 안 함
-1
적수가 없을 때.
물론 항상 확장 방법 뒤에 숨길 수 있습니다.그리고 일치하는 항목이 없을 때 가장 잘 할 수 있는 것은 상황에 따라 크게 달라집니다.
제가 여기에 기여할 것입니다... 왜죠? 단지 :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();
}
여기 제가 방금 작성한 작은 확장자가 있습니다.
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;
}
}
그러면 이렇게 부르면 됩니다.
IEnumerable<Int32> indicesWhereConditionIsMet =
ListItems.Positions(item => item == this);
Int32 firstWelcomeMessage ListItems.Position(msg =>
msg.WelcomeMessage.Contains("Hello"));
다음은 항목을 찾을 수 없을 때 -1을 반환하는 가장 높은 투표를 받은 답변의 구현입니다.
public static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> predicate)
{
var itemsWithIndices = items.Select((item, index) => new { Item = item, Index = index });
var matchingIndices =
from itemWithIndex in itemsWithIndices
where predicate(itemWithIndex.Item)
select (int?)itemWithIndex.Index;
return matchingIndices.FirstOrDefault() ?? -1;
}
언급URL : https://stackoverflow.com/questions/2471588/how-to-get-index-using-linq
'programing' 카테고리의 다른 글
목록을 주문하려면 어떻게 해야 합니까? (0) | 2023.05.23 |
---|---|
UITableView 셀에 UITextField 설정 (0) | 2023.05.23 |
Visual Studio 2019 Azure 기능 CLI 도구를 다시 다운로드합니다. (0) | 2023.05.23 |
이미지가 Visual Studio 디자이너에 표시되지만 런타임에는 표시되지 않음 (0) | 2023.05.18 |
VB.NET에서 문자열을 연결하기 위한 앰퍼샌드 vs. (0) | 2023.05.18 |