2014-10-15 2 views
1

이것은 잠시 전에 게시 한 질문의 후속 조치입니다. 나는 대답을 얻었지만, 원래의 의도를 잃어 버린 지점까지 예제 수업을 단순화했다는 것을 깨달았습니다. 원래 질문에 대한 답변을 이미 수락 했으므로 다른 질문을 시작하는 것이 가장 좋습니다.각 범주에서 가장 높은 가격의 항목을 반환하는 LINQ 쿼리

그래서 여기 내 새로운 클래스의 :

public class Art 
{ 
    public string Type { get; set; } 
    public string Name { get; set; } 
    public int Price { get; set; } 
} 

... 여기 목록 작성입니다 : 내가 싶어하는 개체의 컬렉션, 각 유형에 대한 하나

public static void Example0000() 
{ 
    List<Art> art = new List<Art>(); 
    art.Add(new Art() { Price = 45, Type = "painting", Name = "Still Life in Maryland" }); 
    art.Add(new Art() { Price = 123, Type = "sculpture", Name = "Dying Sheep" }); 
    art.Add(new Art() { Price = 12, Type = "icon", Name = "Perplexed Smiley" }); 
    art.Add(new Art() { Price = 460, Type = "sculpture", Name = "Waves on Sand" }); 
    art.Add(new Art() { Price = 2030, Type = "painting", Name = "Robert in the Morning" }); 
    art.Add(new Art() { Price = 10, Type = "icon", Name = "Smiley Picking Nose" }); 
    art.Add(new Art() { Price = 700, Type = "painting", Name = "Birds in Autumn" }); 
    art.Add(new Art() { Price = 1400, Type = "sculpture", Name = "Holding Hands" }); 
    art.Add(new Art() { Price = 46, Type = "painting", Name = "Reeling Him In" }); 
    art.Add(new Art() { Price = 12000, Type = "sculpture", Name = "Old Dog" }); 
    art.Add(new Art() { Price = 6, Type = "icon", Name = "Hiding Smiley" }); 
    art.Add(new Art() { Price = 810, Type = "sculpture", Name = "Rhinestone Cowgirl" }); 
    art.Add(new Art() { Price = 250, Type = "painting", Name = "Upstairs, Downstairs" }); 
    art.Add(new Art() { Price = 3, Type = "icon", Name = "Dopey Smiley" }); 
    art.Add(new Art() { Price = 1000, Type = "painting", Name = "Young Love" }); 
    art.Add(new Art() { Price = 260, Type = "sculpture", Name = "Taking a Spill" }); 
} 

입니다, 세 가지 속성이 있습니다. ArtType, ArtName 및 MostExpensivePrice가 있습니다. 각 유형에 대해 해당 유형의 최고가 품목에 대한 이름과 가격을 원합니다.

그래서 내 목록이 보일 것 같은 :

painting______Robert_in_the_Morning______2030

sculpture_____Old Dog__________________12000

icon_________Perplexed Smiley______________12

LINQ가에 대한 어떤 모습까요? 시작 예는 다음과 같습니다.

var categories4 = 
    from a in art 
    group a by a.Type into g 
    let maxPrice = g.Max(p => p.Price) 
    select new { ArtType = g.Key, MostExpensive = g.Where(a => a.Price == maxPrice) }; 

답변

1

Enumerable.Aggregate() 메서드를 참조하십시오.

지금까지 주어진 다른 대답은 최대 가격만을 반환합니다. 이는 당신이 여기서 요구하는 것이 아닙니다. 이 같은 Enumerable.Aggregate()를 사용하는 경우 : 당신은 그냥 가격 대신 최대 모든 정보를 표시 할 수

MostExpensive = g.Aggregate((art1, art2) => (art1.Price > art2.Price) ? art1 : art2) 

는, 그런 다음 LINQ 결과는 예술의 인스턴스를 가질 것 대신 단지 int로.

편집 :

var artprices = 
    from a in art 
    group a by a.Type into g 
    let mostExpensive = g.Aggregate((art1, art2) => (art1.Price > art2.Price) ? art1 : art2) 
    select new { ArtType = g.Key, ArtName = mostExpensive.Name, MostExpensivePrice = mostExpensive.Price }; 

그리고 당신은 요소가 세 개의 값을 갖는 결과를해야합니다 : 그것은 위에서 분명 아니었다 경우

는 전체 표현은 다음이 될 수 있습니다 필요.

편집 2 :

그리고 마지막으로, 나는 다른 답변에 의견을 추가 할 수는 없지만, 나는 그들이 다른 방법으로, 모두 부족한 것을 가능한 한 내가 객관적 지적거야 사이트에 새로운 것을 .

하나의 대답은 원본 컬렉션의 모든 요소에 대해 한 번 Max() 메소드를 평가 한 다음 모든 유형 값 (즉, 각 그룹)에 대해 다시 평가할 것을 제안합니다. 이는 매우 작은 데이터 세트에서는 잘 수행되지만 중요한 데이터 콜렉션에서는 절망적 일 수있는 고전적인 O (N^2) 시나리오입니다.

두 개의 다른 대답은 각 개별 그룹의 요소를 정렬하는 것이 좋습니다. 이 방법이 더 좋지만 여전히 메모리 및 성능 오버 헤드가 필요합니다. 일반적인 정렬은 O (N^2)보다 훨씬 낫지 만 여전히 Aggregate()를 사용하는 선형 O (N)만큼 좋지 않습니다. 다시 말하지만, 작은 데이터 세트는 전혀 문제가 없지만, 단순하지 않은 콜렉션은보다 효율적인 접근 방식에 비해 현저한 성능 저하를 가져옵니다.

희망 하시겠습니까?

+0

그것은 좋은 통찰력입니다. 가독성과 성능 사이에 약간의 상충 관계가 있습니다. 그러나 그것은 내부적으로 'Aggregate'를 사용하는 확장 메서드를 만드는 것을 막지는 않지만 Max가 제공 할 수있는 가독성을 제공합니다. (예 : [MaxBy] (https://code.google.com/p/morelinq/source/browse/MoreLinq/MaxBy.cs) 확장 방법) – AtinSkrita

+0

여기에는 많은 좋은 답변이 있었으며, 하나만 선택해야합니다. 이 사람은 제가 창조하려고했던 정신에 가장 잘 대답했습니다. 선택한 Art 개체 집합의 정보가 포함 된 On-The-Fly 개체 모음입니다. –

0

거의 다 왔었습니다. 필요하지 않을 것 같은 let를 제거하고 Price 특성에 Max을 수행가 그룹의 일부가 아니다으로

var categories4 = from a in art 
        group a by a.Type into g 
        select new 
        { 
         ArtType = g.Key, 
         MostExpensive = g.Max(a => a.Price) 
        }; 

복잡한 부분은 예술의 이름을 받고있다. 먼저 동일한 유형의 미술품 2 개가 동일한 최대 가격을 갖는다면 어떻게 될지 결정해야합니다. 당신이 신경 쓰지 않는다면이 일을 할 것입니다 :

var categories4 = from a in art 
        group a by a.Type into g 
        select new 
        { 
         ArtType = g.Key, 
         Name = g.Where(a => a.Price == g.Max(b => b.Price)) 
           .Select(a => a.Name).First(), 
         MostExpensive = g.Max(a => a.Price) 
        }; 
+0

을하지만 그것은 단지 나에게 두 개의 열을 제공합니다. 내 컬렉션에 가장 비싼 아트웍의 이름을 어떻게 추가합니까? –

1

글쎄, 첫 번째 부분은 옳았고, 두 번째 부분은 조금 벗어났습니다. 가장 먼저해야 할 일은 GroupBy 메서드가 반환하는 것을 이해하는 것입니다. GroupBy은 기본적으로 목록 (배열 또는 열거 형의 열거 형) 목록을 반환합니다. 당신로 선언 된 유형을 사용

은 다음과 같습니다

List<Art> art = new List<Art>() 
{ 
    new Art() { Price = 45, Type = "painting", Name = "Still Life in Maryland" }), 
    new Art() { Price = 123, Type = "sculpture", Name = "Dying Sheep" }), 
    new Art() { Price = 12, Type = "icon", Name = "Perplexed Smiley" }), 
    new Art() { Price = 460, Type = "sculpture", Name = "Waves on Sand" });, 
    new Art() { Price = 2030, Type = "painting", Name = "Robert in the Morning" }), 
    new Art() { Price = 10, Type = "icon", Name = "Smiley Picking Nose" }), 
    new Art() { Price = 700, Type = "painting", Name = "Birds in Autumn" }), 
    new Art() { Price = 1400, Type = "sculpture", Name = "Holding Hands" }), 
    new Art() { Price = 46, Type = "painting", Name = "Reeling Him In" }), 
    new Art() { Price = 12000, Type = "sculpture", Name = "Old Dog" }), 
    new Art() { Price = 6, Type = "icon", Name = "Hiding Smiley" }), 
    new Art() { Price = 810, Type = "sculpture", Name = "Rhinestone Cowgirl" }), 
    new Art() { Price = 250, Type = "painting", Name = "Upstairs, Downstairs" }), 
    new Art() { Price = 3, Type = "icon", Name = "Dopey Smiley" }), 
    new Art() { Price = 1000, Type = "painting", Name = "Young Love" }), 
    new Art() { Price = 260, Type = "sculpture", Name = "Taking a Spill" }) 
} 

다음과 같습니다 예술 뭔가 결과 목록 그룹화 :

IEnumerable<IGrouping<string, Art>> groupedByType = art.GroupBy(a => a.Type); 
를이 데이터와

public class Art 
{ 
    public string Type { get; set; } 
    public string Name { get; set; } 
    public int Price { get; set; } 
} 

여기서 각 IGrouping<string, Art>에는 Art의 목록이 들어 있으며 목록의 각 부분에는 같은 Type. 두 번째 단계로이 촬영, 우리는 단지 각 그룹에서 최고 가격을 선택해야합니다

IEnumerable<Art> maxFromEachGroup = groupedByType 
    // Take a single piece of art from each group 
    .Select(group => 
     // Get the maximum piece of art by ordering from largest to smallest 
     // and taking the first 
     group.OrderByDescending(a => a.Price).First() 
    ); 

이제 각 그룹에서 가장 비싼 조각이 포함되어 Art의 목록을 가지고있다. Max으로 알고 있어야 할 점은 최대 가격의 Art 조각을 반환하는 것과 비교할 때 최대 가격의 값을 반환한다는 것입니다. 이와 같이 LINQ 표현식의 전체 표현식은 다음과 같습니다.

var maxFromEachGroup = from a in art 
         group a by a.Type into g 
         select (from a in g orderby a.Price descending select a).First(); 
1

이 방법이 효과가 있습니까?

var query = 
    art 
     .OrderByDescending(x => x.Price) 
     .GroupBy(x => x.Type) 
     .Select(x => x.First()); 

나는이 결과 얻을 :

Query Result

관련 문제