Linqのリストから複数のフィールドを選択


128

ASP.NET C#には構造体があります。

public struct Data
{
    public int item1;
    public int item2;
    public int category_id;
    public string category_name;
}

そして私はそれらのリストを持っています。category_idand を選択してcategory_name実行しDISTINCT、最後にORDERBYonにしcategory_nameます。

これが私が今持っているものです:

List<Data> listObject = getData();
string[] catNames = listObject
                    .Select(i=> i.category_name)
                    .Distinct()
                    .OrderByDescending(s => s)
                    .ToArray();

これは明らかにカテゴリ名を取得するだけです。私の質問は、どのようにして複数のフィールドを取得し、どのデータ構造をこれに保存するのstring[]ですか?

編集

構造体のリストを使用することは難しいことではありません。選択を簡単にするためにバッキングデータ構造を変更することが望ましい場合(これらの多くを記述します)、喜んで推奨事項を採用します。


10
LINQ側とは関係ありませんが、可変構造体やパブリックフィールドを使用しないことを強くお勧めします。個人的に私が最初に構造体を作成することはめったにありませんが、変更可能な構造体は単に問題を求めています。
Jon Skeet、

@ジョンスキートありがとう。プライベートメンバーを含む通常のクラスに変換します。
チェット

1
@Midhat:可変構造体は、人々が期待するように動作しないため、あらゆる種類の問題を引き起こします。そして、パブリックフィールドはカプセル化を完全に欠いています。
Jon Skeet、

@ジョンスキート。変更可能な構造体の落とし穴についてもっと具体的に説明できますか、それとも私に読書を指摘してください。
ミッドハット

2
@Midhat:出発点として、stackoverflow.com / questions / 441309 / why-are-mutable-structs-evilをご覧ください。
Jon Skeet、

回答:


228

匿名型を使用すると、任意のフィールドをデータ構造に選択して、後でコードで強く型付けすることができます。

var cats = listObject
    .Select(i => new { i.category_id, i.category_name })
    .Distinct()
    .OrderByDescending(i => i.category_name)
    .ToArray();

(どうやら)それを後で使用するために保存する必要があるので、GroupBy演算子を使用できます。

Data[] cats = listObject
    .GroupBy(i => new { i.category_id, i.category_name })
    .OrderByDescending(g => g.Key.category_name)
    .Select(g => g.First())
    .ToArray();

1つの列で個別を使用して複数の列を取得したいのですが、どうすればよいですか?
Kishan Gajjar

1
Select新しいタイプを思いついたことはありません。私の場合、新しいを選択しましたKeyValuePair
cjbarth 2013年

26
var selectedCategories =
    from value in
        (from data in listObject
        orderby data.category_name descending
        select new { ID = data.category_id, Name = data.category_name })
    group value by value.Name into g
    select g.First();

foreach (var category in selectedCategories) Console.WriteLine(category);

編集:よりLINQ-eyにした!


ハハ、ありがとう、まあ、私は助けに感謝します。どうやら、これは世界で最も難しい問題ではありませんでした。
チェット

@IRBMeすみません、小さな質問です。正確に「値」とは何ですか?
Fernando S. Kroes、

23

匿名型を使用できます:

.Select(i => new { i.name, i.category_name })

コンパイラーは、nameおよびcategory_nameプロパティを持つクラスのコードを生成し、そのクラスのインスタンスを返します。プロパティ名を手動で指定することもできます。

i => new { Id = i.category_id, Name = i.category_name }

プロパティはいくつでも持つことができます。


6

さまざまな例で上記のようにlinq Selectを使用して複数のフィールドを選択できます。これは匿名型として返されます。この匿名型を避けたい場合は、ここに簡単なトリックがあります。

var items = listObject.Select(f => new List<int>() { f.Item1, f.Item2 }).SelectMany(item => item).Distinct();

これで問題は解決すると思います


5

これは、匿名型が非常に適しているタスクです。使用法から推測される、コンパイラーによって自動的に作成されるタイプのオブジェクトを返すことができます。

構文は次の形式です。

new { Property1 = value1, Property2 = value2, ... }

あなたのケースでは、次のようなことを試してください:

var listObject = getData();
var catNames = listObject.Select(i =>
    new { CatName = i.category_name, Item1 = i.item1, Item2 = i.item2 })
    .Distinct().OrderByDescending(s => s).ToArray();

4
var result = listObject.Select( i => new{ i.category_name, i.category_id } )

これは匿名型を使用するため、式の結果の型は事前にわからないため、varキーワードを使用する必要があります。



3

KeyValuePairにすることができるので、 "IEnumerable<KeyValuePair<string, string>>"

したがって、次のようになります。

.Select(i => new KeyValuePair<string, string>(i.category_id, i.category_name )).Distinct();

これにより、メリットなしに不必要な複雑さが追加されます
Matze

2
public class Student
{
    public string Name { set; get; }
    public int ID { set; get; }
}

class Program
{
  static void Main(string[] args)
    {
        Student[] students =
        {
        new Student { Name="zoyeb" , ID=1},
        new Student { Name="Siddiq" , ID=2},
        new Student { Name="sam" , ID=3},
        new Student { Name="james" , ID=4},
        new Student { Name="sonia" , ID=5}
        };

        var studentCollection = from s in students select new { s.ID , s.Name};

        foreach (var student in studentCollection)
        {
            Console.WriteLine(student.Name);
            Console.WriteLine(student.ID);
        }
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.