그래서 오늘 흥미로운 문제를 발견했습니다. IList를 반환하는 WCF 웹 서비스가 있습니다. 내가 그것을 분류하고 싶을 때까지별로 큰 문제는 아닙니다.
IList 인터페이스에는 정렬 메서드가 내장되어 있지 않습니다.
나는 결국 ArrayList.Adapter(list).Sort(new MyComparer())
문제를 해결하기 위해 방법을 사용 했지만 그것은 나에게 약간 “빈민가”처럼 보였다.
나는 확장 메서드를 작성하고 IList에서 상속하고 자체 Sort () 메서드를 구현하고 List로 캐스팅하는 데 놀랐지 만 이들 중 어느 것도 지나치게 우아하게 보이지 않았습니다.
그래서 내 질문은 누구든지 IList 정렬에 대한 우아한 해결책이 있습니까?
답변
LINQ To Objects를 사용하여 정렬하는 것은 어떻습니까?
당신이 가지고 있고 IList<Car>
차에 Engine
재산이 있다고 가정하면 다음과 같이 분류 할 수 있다고 생각합니다.
from c in list
orderby c.Engine
select c;
편집 : 여기에서 답을 얻으려면 빨리해야합니다. 다른 답변과 약간 다른 구문을 제시 했으므로 답변을 남기겠습니다. 그러나 제시된 다른 답변은 똑같이 유효합니다.
답변
LINQ를 사용할 수 있습니다.
using System.Linq;
IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();
답변
이 질문에 영감을 받아 블로그 게시물을 작성했습니다. http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
이상적으로는 .NET Framework에 IList <T>를 허용하는 정적 정렬 메서드가 포함되어 있다고 생각하지만 다음으로 좋은 방법은 사용자 고유의 확장 메서드를 만드는 것입니다. List <T>처럼 IList <T>를 정렬 할 수있는 몇 가지 메서드를 만드는 것은 그리 어렵지 않습니다. 보너스로 동일한 기술을 사용하여 LINQ OrderBy 확장 메서드를 오버로드 할 수 있으므로 List.Sort, IList.Sort 또는 IEnumerable.OrderBy를 사용하든 똑같은 구문을 사용할 수 있습니다.
public static class SortExtensions
{
// Sorts an IList<T> in place.
public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
{
ArrayList.Adapter((IList)list).Sort(new ComparisonComparer<T>(comparison));
}
// Sorts in IList<T> in place, when T is IComparable<T>
public static void Sort<T>(this IList<T> list) where T: IComparable<T>
{
Comparison<T> comparison = (l, r) => l.CompareTo(r);
Sort(list, comparison);
}
// Convenience method on IEnumerable<T> to allow passing of a
// Comparison<T> delegate to the OrderBy method.
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison)
{
return list.OrderBy(t => t, new ComparisonComparer<T>(comparison));
}
}
// Wraps a generic Comparison<T> delegate in an IComparer to make it easy
// to use a lambda expression for methods that take an IComparer or IComparer<T>
public class ComparisonComparer<T> : IComparer<T>, IComparer
{
private readonly Comparison<T> _comparison;
public ComparisonComparer(Comparison<T> comparison)
{
_comparison = comparison;
}
public int Compare(T x, T y)
{
return _comparison(x, y);
}
public int Compare(object o1, object o2)
{
return _comparison((T)o1, (T)o2);
}
}
이러한 확장을 사용하여 목록과 마찬가지로 IList를 정렬합니다.
IList<string> iList = new []
{
"Carlton", "Alison", "Bob", "Eric", "David"
};
// Use the custom extensions:
// Sort in-place, by string length
iList.Sort((s1, s2) => s1.Length.CompareTo(s2.Length));
// Or use OrderBy()
IEnumerable<string> ordered = iList.OrderBy((s1, s2) => s1.Length.CompareTo(s2.Length));
게시물에 더 많은 정보가 있습니다 : http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
답변
당신은 내가 생각하는 것과 같은 것을해야 할 것입니다 (더 구체적인 유형으로 변환하십시오).
ArrayList가 아닌 List of T로 가져 가면 유형 안전성과 비교자를 구현하는 방법에 대한 더 많은 옵션을 얻을 수 있습니다.
답변
@DavidMills가 받아 들인 대답은 꽤 좋지만 개선 될 수 있다고 생각합니다. 하나의 ComparisonComparer<T>
경우 프레임 워크에 이미 정적 메서드가 포함되어있는 경우 클래스 를 정의 할 필요가 없습니다 Comparer<T>.Create(Comparison<T>)
. 이 메서드는 IComparison
즉석 에서 생성하는 데 사용할 수 있습니다 .
또한, 캐스트 IList<T>
에 IList
어떤 위험 할 수있는 잠재력을 가지고있다. 내가 본 대부분의 경우 List<T>
어떤 구현 IList
이을 구현 하는 데 백그라운드에서 사용 IList<T>
되지만 이는 보장되지 않으며 부서지기 쉬운 코드로 이어질 수 있습니다.
마지막으로 오버로드 된 List<T>.Sort()
메서드에는 4 개의 서명이 있으며 그중 2 개만 구현됩니다.
List<T>.Sort()
List<T>.Sort(Comparison<T>)
List<T>.Sort(IComparer<T>)
List<T>.Sort(Int32, Int32, IComparer<T>)
아래 클래스 List<T>.Sort()
는 IList<T>
인터페이스에 대한 4 개의 서명을 모두 구현합니다 .
using System;
using System.Collections.Generic;
public static class IListExtensions
{
public static void Sort<T>(this IList<T> list)
{
if (list is List<T>)
{
((List<T>)list).Sort();
}
else
{
List<T> copy = new List<T>(list);
copy.Sort();
Copy(copy, 0, list, 0, list.Count);
}
}
public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
{
if (list is List<T>)
{
((List<T>)list).Sort(comparison);
}
else
{
List<T> copy = new List<T>(list);
copy.Sort(comparison);
Copy(copy, 0, list, 0, list.Count);
}
}
public static void Sort<T>(this IList<T> list, IComparer<T> comparer)
{
if (list is List<T>)
{
((List<T>)list).Sort(comparer);
}
else
{
List<T> copy = new List<T>(list);
copy.Sort(comparer);
Copy(copy, 0, list, 0, list.Count);
}
}
public static void Sort<T>(this IList<T> list, int index, int count,
IComparer<T> comparer)
{
if (list is List<T>)
{
((List<T>)list).Sort(index, count, comparer);
}
else
{
List<T> range = new List<T>(count);
for (int i = 0; i < count; i++)
{
range.Add(list[index + i]);
}
range.Sort(comparer);
Copy(range, 0, list, index, count);
}
}
private static void Copy<T>(IList<T> sourceList, int sourceIndex,
IList<T> destinationList, int destinationIndex, int count)
{
for (int i = 0; i < count; i++)
{
destinationList[destinationIndex + i] = sourceList[sourceIndex + i];
}
}
}
용법:
class Foo
{
public int Bar;
public Foo(int bar) { this.Bar = bar; }
}
void TestSort()
{
IList<int> ints = new List<int>() { 1, 4, 5, 3, 2 };
IList<Foo> foos = new List<Foo>()
{
new Foo(1),
new Foo(4),
new Foo(5),
new Foo(3),
new Foo(2),
};
ints.Sort();
foos.Sort((x, y) => Comparer<int>.Default.Compare(x.Bar, y.Bar));
}
여기서 아이디어는 List<T>
가능한 한 정렬을 처리하기 위해 기본 기능을 활용하는 것입니다 . 다시 말하지만, IList<T>
내가 본 대부분의 구현은 이것을 사용합니다. 기본 컬렉션이 다른 유형 인 List<T>
경우 입력 목록의 요소를 사용하여 새 인스턴스를 만드는 것으로 대체하고 이를 사용하여 정렬 한 다음 결과를 다시 입력 목록에 복사합니다. 이는 입력 목록이 IList
인터페이스를 구현하지 않는 경우에도 작동합니다 .
답변
try this **USE ORDER BY** :
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
}
private static IList<Employee> GetItems()
{
List<Employee> lst = new List<Employee>();
lst.Add(new Employee { Id = "1", Name = "Emp1" });
lst.Add(new Employee { Id = "2", Name = "Emp2" });
lst.Add(new Employee { Id = "7", Name = "Emp7" });
lst.Add(new Employee { Id = "4", Name = "Emp4" });
lst.Add(new Employee { Id = "5", Name = "Emp5" });
lst.Add(new Employee { Id = "6", Name = "Emp6" });
lst.Add(new Employee { Id = "3", Name = "Emp3" });
return lst;
}
**var lst = GetItems().AsEnumerable();
var orderedLst = lst.OrderBy(t => t.Id).ToList();
orderedLst.ForEach(emp => Console.WriteLine("Id - {0} Name -{1}", emp.Id, emp.Name));**
답변
원래 게시물에 설명 된 정확한 문제에 대한 해결책을 찾고있는 동안이 스레드를 찾았습니다. 그러나 대답 중 어느 것도 내 상황을 완전히 충족시키지 못했습니다. Brody의 대답은 매우 가깝습니다. 여기에 내 상황과 해결책이 있습니다.
나는 NHibernate에 의해 반환 된 동일한 유형의 두 개의 IList를 가지고 있으며 두 개의 IList를 하나로 이머 지했기 때문에 정렬이 필요합니다.
Brody가 말했듯이 IList의 유형 인 개체 (ReportFormat)에 ICompare를 구현했습니다.
public class FormatCcdeSorter:IComparer<ReportFormat>
{
public int Compare(ReportFormat x, ReportFormat y)
{
return x.FormatCode.CompareTo(y.FormatCode);
}
}
그런 다음 병합 된 IList를 동일한 유형의 배열로 변환합니다.
ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList
그런 다음 배열을 정렬합니다.
Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer
1 차원 배열이 인터페이스를 구현 System.Collections.Generic.IList<T>
하므로 원래 IList처럼 배열을 사용할 수 있습니다.