次のようなクラスがあるとしましょう。
class Person {
internal int PersonID;
internal string car ;
}
今、私はこのクラスのリストを持っています:List<Person> persons;
このリストには、同じPersonIDを持つ複数のインスタンスを含めることができます。次に例を示します。
persons[0] = new Person { PersonID = 1, car = "Ferrari" };
persons[1] = new Person { PersonID = 1, car = "BMW" };
persons[2] = new Person { PersonID = 2, car = "Audi" };
personID
でグループ分けして、彼が持っているすべての車のリストを取得する方法はありますか?
たとえば、期待される結果は次のようになります。
class Result {
int PersonID;
List<string> cars;
}
それで、グループ化した後、私は得るでしょう:
results[0].PersonID = 1;
List<string> cars = results[0].cars;
result[1].PersonID = 2;
List<string> cars = result[1].cars;
私がこれまでにやったことから:
var results = from p in persons
group p by p.PersonID into g
select new { PersonID = g.Key, // this is where I am not sure what to do
誰かが私を正しい方向に向けてください。
絶対に - あなたは基本的に欲しい:
var results = from p in persons
group p.car by p.PersonId into g
select new { PersonId = g.Key, Cars = g.ToList() };
または非クエリ式として:
var results = persons.GroupBy(
p => p.PersonId,
p => p.car,
(key, g) => new { PersonId = key, Cars = g.ToList() });
基本的にグループの内容は(IEnumerable<T>
として表示されるとき)、与えられたキーに存在する射影(この場合はp.car
)に含まれていた値のシーケンスです。
GroupBy
の仕組みの詳細については、私の トピックに関するEdulinqの投稿 を参照してください。
(上記では、 .NET命名規則 に従うためにPersonID
をPersonId
に名前変更しました。)
あるいは、Lookup
を使用することもできます。
var carsByPersonId = persons.ToLookup(p => p.PersonId, p => p.car);
そうすれば、一人一人の車をとても簡単に手に入れることができます。
// This will be an empty sequence for any personId not in the lookup
var carsForPerson = carsByPersonId[personId];
var results = from p in persons
group p by p.PersonID into g
select new { PersonID = g.Key,
/**/car = g.Select(g=>g.car).FirstOrDefault()/**/}
var results = from p in persons
group p by p.PersonID into g
select new { PersonID = g.Key, Cars = g.Select(m => m.car) };
あなたもこれを試すことができます。
var results= persons.GroupBy(n => new { n.PersonId, n.car})
.Select(g => new {
g.Key.PersonId,
g.Key.car)}).ToList();
やってみる
persons.GroupBy(x => x.PersonId).Select(x => x)
または
誰かがあなたのリストで繰り返しているかどうかを確認するために試してみてください
persons.GroupBy(x => x.PersonId).Where(x => x.Count() > 1).Any(x => x)
クエリ構文とメソッド構文を使った実用的なコードサンプルを作成しました。私はそれが他の人に役立つことを願っています:)
コードを.Net Fiddleここで実行することもできます。
using System;
using System.Linq;
using System.Collections.Generic;
class Person
{
public int PersonId;
public string car ;
}
class Result
{
public int PersonId;
public List<string> Cars;
}
public class Program
{
public static void Main()
{
List<Person> persons = new List<Person>()
{
new Person { PersonId = 1, car = "Ferrari" },
new Person { PersonId = 1, car = "BMW" },
new Person { PersonId = 2, car = "Audi"}
};
//With Query Syntax
List<Result> results1 = (
from p in persons
group p by p.PersonId into g
select new Result()
{
PersonId = g.Key,
Cars = g.Select(c => c.car).ToList()
}
).ToList();
foreach (Result item in results1)
{
Console.WriteLine(item.PersonId);
foreach(string car in item.Cars)
{
Console.WriteLine(car);
}
}
Console.WriteLine("-----------");
//Method Syntax
List<Result> results2 = persons
.GroupBy(p => p.PersonId,
(k, c) => new Result()
{
PersonId = k,
Cars = c.Select(cs => cs.car).ToList()
}
).ToList();
foreach (Result item in results2)
{
Console.WriteLine(item.PersonId);
foreach(string car in item.Cars)
{
Console.WriteLine(car);
}
}
}
}
これが結果です。
1 フェラーリ BMW 2 アウディ ----------- ] 1 フェラーリ BMW 2 アウディ
これを試して :
var results= persons.GroupBy(n => n.PersonId)
.Select(g => new {
PersonId=g.Key,
Cars=g.Select(p=>p.car).ToList())}).ToList();
しかし、パフォーマンス的には、次のプラクティスの方がメモリ使用量の点で優れており、より最適化されています(配列に数百万の項目が含まれる場合)。
var carDic=new Dictionary<int,List<string>>();
for(int i=0;i<persons.length;i++)
{
var person=persons[i];
if(carDic.ContainsKey(person.PersonId))
{
carDic[person.PersonId].Add(person.car);
}
else
{
carDic[person.PersonId]=new List<string>(){person.car};
}
}
//returns the list of cars for PersonId 1
var carList=carDic[1];
これを行うための別の方法は、異なるPersonId
を選択し、グループをpersons
で結合することです。
var result =
from id in persons.Select(x => x.PersonId).Distinct()
join p2 in persons on id equals p2.PersonId into gr // apply group join here
select new
{
PersonId = id,
Cars = gr.Select(x => x.Car).ToList(),
};
流暢なAPI構文でも同じです。
var result = persons.Select(x => x.PersonId).Distinct()
.GroupJoin(persons, id => id, p => p.PersonId, (id, gr) => new
{
PersonId = id,
Cars = gr.Select(x => x.Car).ToList(),
});
GroupJoin は、最初のリスト(この場合はPersonId
のリスト)にエントリのリストを作成し、それぞれが2番目のリスト(persons
のリスト)に結合されたエントリのグループを持ちます。