c# 언어 - LINQ를 사용하여 100 위와 100 위를 차지합니까?



가이드 문서 (5)

다음과 같은 확장 메서드를 사용할 수 있습니다.

public static IEnumerable<T> TakeFirstAndLast<T>(this IEnumerable<T> source, int count)
{
    var first = new List<T>();
    var last = new LinkedList<T>();
    foreach (var item in source)
    {
        if (first.Count < count)
            first.Add(item);
        if (last.Count >= count)
            last.RemoveFirst();
        last.AddLast(item);
    }

    return first.Concat(last);
}

(내가 O(1) 에서 항목을 제거 할 수 있기 때문에 last 으로 LinkedList<T> 를 사용하고 있습니다)

다음과 같이 사용할 수 있습니다.

.Orderby(i => i.Value1)
.TakeFirstAndLast(100)
.Orderby(i => i.Value2);

200 개 미만의 항목이있는 경우에는 처리하지 않습니다.이 경우 항목이 중복됩니다. 필요한 경우 Distinct 사용하여 제거 할 수 있습니다.

나는 (아래)와 같은 것을하고 싶다. 그렇지만 정식 / 최적화 구문이 있다면 그렇게 할 것인가?

.Orderby(i => i.Value1)
.Take("Bottom 100 & Top 100")
.Orderby(i => i.Value2);

기본적으로 하나의 변수로 정렬 한 다음 상위 100 개와 하위 100 개를 취하고 그 결과를 다른 변수로 정렬하려고합니다.

어떤 제안?


당신은 또한 이것을 사용하여 하나의 명령문으로 이것을 할 수 있습니다. 사용 가능한 요소의 수가 많은 경우 오버로드가 발생합니다.

var elements = ...

var count = elements.Length; // or .Count for list

var result = elements
    .OrderBy(i => i.Value1)
    .Where((v, i) => i < 100 || i >= count - 100)
    .OrderBy(i => i.Value2)
    .ToArray();             // evaluate

다음은 작동 방식입니다.

| first 100 elements | middle elements | last 100 elements |
        i < 100        i < count - 100    i >= count - 100

상위 100과 하위 100을 따로 따로 가지고 결합하십시오 :

var tempresults = yourenumerable.OrderBy(i => i.Value1);
var results = tempresults.Take(100);
results = results.Union(tempresults.Skip(tempresults.Count() - 100).Take(100))
                 .OrderBy(i => i.Value2);

Enumerable 클래스에서 Take() , Skip() 및 기타 메서드와 같은 자체 확장 메서드를 작성할 수 있습니다. 목록의 요소 수와 전체 길이를 입력으로 사용합니다. 그런 다음 시퀀스에서 첫 번째와 마지막 N 개 요소를 반환합니다.

var result = yourList.OrderBy(x => x.Value1)
                     .GetLastAndFirst(100, yourList.Length)
                     .OrderBy(x => x.Value2)
                     .ToList();

다음은 확장 메소드입니다.

public static class SOExtensions
{
    public static IEnumerable<T> GetLastAndFirst<T>(
        this IEnumerable<T> seq, int number, int totalLength
    )
    {
        if (totalLength < number*2) 
            throw new Exception("List length must be >= (number * 2)");

        using (var en = seq.GetEnumerator())
        {
            int i = 0;

            while (en.MoveNext())
            {
                i++;
                if (i <= number || i >= totalLength - number) 
                     yield return en.Current;
            }
        }
    }
}

.ThenBy(aPerson=>field2); 사용하십시오 .ThenBy(aPerson=>field2);





c# linq