Linq Составление списка тегов со счетчиком из внутренней коллекции внешней коллекции - PullRequest
1 голос
/ 03 апреля 2011

Я пытаюсь написать один запрос Linq, который может объединять внутренние коллекции тегов из внешней коллекции родительских продуктов и возвращать коллекцию тегов с консолидированным числом, упорядоченным по убыванию по количеству.

Вот рабочее решение, которое у меня есть в настоящее время, и мне нужна помощь для преобразования в один запрос Linq.

Module Module1

Class Tag
    Property Name As String
    Property Count As Integer
End Class

Class Product
    Property Name As String
    Property tags As List(Of Tag)
End Class

Sub Main()

    Dim Products As New List(Of Product) From {
            {New Product With {.Name = "P1",
                               .tags = New List(Of Tag) From {{New Tag With {.Name = "T1"}},
                                                              {New Tag With {.Name = "T3"}},
                                                              {New Tag With {.Name = "T5"}}
                                                             }
                              }
            },
            {New Product With {.Name = "P2",
                               .tags = New List(Of Tag) From {{New Tag With {.Name = "T2"}},
                                                              {New Tag With {.Name = "T4"}},
                                                              {New Tag With {.Name = "T6"}}
                                                             }
                              }
            },
            {New Product With {.Name = "P3",
                               .tags = New List(Of Tag) From {{New Tag With {.Name = "T2"}},
                                                              {New Tag With {.Name = "T3"}},
                                                              {New Tag With {.Name = "T4"}}
                                                             }
                              }
            },
            {New Product With {.Name = "P4",
                               .tags = New List(Of Tag) From {{New Tag With {.Name = "T4"}},
                                                              {New Tag With {.Name = "T5"}},
                                                              {New Tag With {.Name = "T6"}},
                                                              {New Tag With {.Name = "T7"}},
                                                              {New Tag With {.Name = "T8"}}
                                                             }
                              }
            }
        }


    Dim ReportingTags As New List(Of Tag)

    '-- Start : Needs to be converted to pure Linq (if possible)------------------------------------------

    Dim InterimTags As New List(Of String)

    For Each p As Product In Products
        Dim TmpTags As New List(Of String)
        InterimTags.AddRange(TmpTags.Concat(From t In p.tags Select t.Name))
    Next

    ReportingTags.AddRange((From t In InterimTags
                            Group By name = t Into Count = Count()
                            Select New Tag With {.Name = name,
                                                 .Count = Count}).OrderByDescending(Function(t) t.Count))

    '-- End ----------------------------------------------------------------------------------------------

    For Each t As Tag In ReportingTags
        Console.WriteLine("Tag: {0} - Count: {1}", t.Name, t.Count)
    Next

    Console.ReadLine()

End Sub

Конечный модуль

Я возьму вывод и преобразую его в наблюдаемую коллекцию (из TagModel) - поэтому я пытаюсь исключить двойную / тройную обработку данных.

Спасибо

Graeme

1 Ответ

0 голосов
/ 03 апреля 2011

Я парень на C #, но Linq - это Linq, поэтому я решила, что сделаю удар.Я смог сопоставить ваши результаты, поместив в ваш красный раздел следующее:

Dim outStuff = From t In Products.SelectMany(Function(p) p.tags)
               Group By tagName = t.Name
               Into g = Group, Count()
               Order By Count Descending

И затем я использовал

For Each t In outStuff
    Console.WriteLine("Tag: {0} - Count: {1}", t.tagName, t.Count)
Next

, чтобы сделать вывод.

IУверен, что это не самый изящный или элегантный VB, и вы, вероятно, можете улучшить Linq, чтобы он был немного красивее, но это должно стать хорошим началом для вас.

Пример кода в вашем вопросе помогмногое сделать для этого.

Для быстрого объяснения, если вы не знакомы с SelectMany или Group By, они делают несколько разных и чрезвычайно полезных вещей.

SelectMany работает следующим образомВыберите, за исключением того, что при применении к свойству коллекции содержимое всех свойств коллекции выравнивается и возвращается как одна коллекция соответствующего типа, а не возвращается как коллекция коллекций.В этом случае он получает все теги из всех продуктов и помещает их в одну коллекцию для работы.

Group By делает нечто противоположное, берет большую плоскую группу и превращает ее вколлекция коллекций, сгруппированных в соответствии с обозначенными критериями (т. имя в данном случае).

...