2009-09-18 6 views
2

나는 사소한 일을 놓치고있는 것 같습니다.LINQ로 사용자 지정 정렬

어쨌든, 여기 간다 :

var order = new[]{1,3,2}; 
var foos = new[]{new Foo{Id=1}, new Foo{Id=2}, new Foo{Id=3}}; 

어떻게 Linq에를 사용하여 순서 배열하여, FOOS을 정렬?

원하는 결과 :

foos == new[]{new Foo{Id=1}, new Foo{Id=3}, new Foo{Id=2}}; 

편집 :
주문 푸 ID를 포함합니다. 미안하지만 그 말은하지 않았다. 때로는 질문에 답하는 것보다 제대로 질문하는 것이 더 어렵습니다. :) 좋아

+0

'order' 배열은 배열 인덱스 또는'Foo'의'Id'를 지정합니까? –

+0

실제로 - 질문을 명확히하십시오. 나는 당신이 내 대답에서 묻고 있다고 생각하는 것에 대한 설명을했지만, 나는 단지 짐작하고있다. (예를 들어 Dale Halliwell은 다른 의미로 추측합니다.) –

답변

3

는 질문은 나에게 완전히 명확하지 않는 것, 그래서 내가 당신이 요구하는지 생각 무엇인지 명확히하려고합니다 :

  • 당신을
  • 당신은 싶어하지만, 해당 ID를 원하는 순서
  • 당신은 개체의 컬렉션, 올바른 순서에 하지이, ID의 순서를 가지고 ID 순서와 같은 순서로 오브젝트의 컬렉션

올바른가? 것

는 :

var orderedFoos = from orderedId in order 
        join foo in foos on orderedId equals foo.Id into groups 
        select groups.Single(); 

당신은 당신이 누락이 있거나 foos에 ID를 중복되지 않는지 확인하기 위해 join ... into이 필요합니다. 그러나 order에 ID가 누락되었거나 중복 된 것을 감지하지는 않습니다. 당신이 모든 것이 올바른 것이라고 알고있는 경우 (즉 order 반대의 경우도 마찬가지의 모든 항목에 대한 foos 정확히 하나 개의 항목이있을 것) 후 간단한 가입은 괜찮 :

점 표기법으로 표현 될 수있다
var orderedFoos = from orderedId in order 
        join foo in foos on orderedId equals foo.Id 
        select foo; 

:

var orderedFoos = order.Join(foos, order => order, foo => foo.ID, (o, f) => f); 
+0

이 문제가 해결되지 않는다고 생각합니다. 나는 OP가 기본적으로 특정한 ** Id **를 특정 위치에 가지고있는'Foo'를 움켜 잡고 싶어한다고 생각합니다. –

+0

죄송합니다. .NET 4.0을 사용할 수 없습니다. –

+0

@Arnis : 그래서 MoreLINK에 링크 된 것입니다. 그러나 문제를 오해하고 있습니다. –

3
from o in order.Select((o, i) => new { o, i }) 
join f in foos on o.o equals f.Id 
orderby o.i 
select f; 
+2

왜 'o.i'로 주문 했습니까? 그것은 이미 그 순서대로 될 것입니다. –

+0

SQL로 인한 피해가 발생했을 것입니다. – erikkallen

+0

자세히 설명해 드리겠습니다 : 주문하지 않으면 어떤 순서 (있는 경우)가 주문 보존인지 알고 있어야합니다. 개체에 대한 LINQ의 연산자에 대해서는 잘 정의되어있을 수 있지만 LINQ to SQL 인 경우에는 그렇지 않습니다. 또한 문서를 잘못 읽은 경우 orderby를 생략하여 찾기 힘든 버그를 도입 할 수 있습니다 (3 개 항목 만 테스트 한 경우 구현을 모르기 때문에 실수로 1/6의 기회가 있다고 가정 함). 세부). orderby를 추가함으로써 나는 누구에게 상처를 입히지 않고 이러한 문제들을 제거합니다. – erikkallen

0
var order = new[] { 1, 3, 2 }; 
var foos = new[] { new Foo { Id = 1 }, new Foo { Id = 2 }, new Foo { Id = 3 } }; 

var query = from o in order 
      join foo in foos on o equals foo.Id 
      select foo; 

var foos2 = query.ToArray(); 
1

아마 주문 조회 O를 만들기 위해 쌍을 주문/아이디의 Dictionary<int,int>을 사용하십시오 (1) 내가 할 수있는 이들의 많은이 있다면. 주문에서 값이 누락 된 사례도 처리해야합니다. 마지막으로 이동하도록 선택했습니다.

var order = new Dictionary<int,int>(); 
order.Add(1, 1); 
order.Add(2, 3); 
order.Add(3, 2); 

var orderedFoos = foos.OrderBy(f => order.Contains(f.Id) ? order[f.Id] : int.MaxValue); 
+0

성능은 여기에 문제가되지 않으며 값이 일치해야합니다 (아무 래도하지 않으면 예외는 있지만). 감사합니다. :) –

4

어떻게 하시겠습니까? 당신은 중첩 된 쿼리를 사용하여이 작업을 수행 할 수 있습니다 1,3,2

+1

조인을 기반으로 한 이러한 답변 중 일부는 대형 세트보다 훨씬 비싸며이 작은 LINQ는 비교자를 사용합니다. –

+0

나는 당신의 대답이 다른 모든 대답에 대해 다른 일을한다고 생각합니다. 그것은 또한 O (n)이어야하는 조인보다 * 더 비싸다 - 당신의 대답은 O (n log n)이다. –

+0

답의 차이점에 관해서는 ... 당신은'foos'가 이미 순서대로 있다고 가정하고 있으며, 간격이없는 ID 1, 2, 3, 4를 가질 것입니다. –

1

하지만 O(n²)와 매우 비효율적이다 : 당신이 ID를 인쇄, 그 출력 지금 foreach는 경우

foos.OrderBy(f => order[f.Id-1]); 

, 당신은 얻을.

var result = order.Select(o => foos.Single(f => f.Id == o)); 

', FOOS'에 존재하지 않는 ID를 포함 할 수있다 '순서', 당신은 SingleOrDefault()를 사용해야합니다. foos에 중복 ID가 포함되어있는 경우 First() 또는 FirstOrDefault()을 사용해야합니다.

var result = order 
    .Select(o => foos.FirstOrDefault(f => f.Id == o)) 
    .Select(f => f != null); 

조차 조인해도 작동하지만 주문을 유지하는지 확신 할 수 없습니다.

var result = Enumerable.Join(order, foos, o => o, f => f.Id, (o, f) => f); 

Jon이 언급했듯이 입력이 첫 번째 제안에서 요구하는 것과 같은 방식으로 잘 형성되는 경우에만 올바르게 작동합니다.

+1

조인은 LINQ to Objects에서 순서를 유지하지만 중복되거나 누락 된 행으로 끝날 수 있습니다. –

+0

"var result = order.Select (o => foos.Single (f => f.Id == o));" 이것은 Mehrdid가 처음에 게시 한 것입니다 (삭제되었습니다). 실제로 이것은 성능이 전혀 문제가되지 않기 때문에이 경우 유효한 접근 방식입니다. 어쨌든 감사합니다. –

관련 문제