Для структурирования данных можно использовать способ, которым вы задаете LINQ ToLookup method
. Из MSDN:
Метод ToLookup
возвращает Lookup
, словарь «один ко многим», который сопоставляет ключи с коллекциями значений. Lookup
отличается от Dictionary
, который выполняет однозначное сопоставление ключей с отдельными значениями.
Чтобы создать Lookup
с использованием метода ToLookup
, мы должны определить:
key
класс с переопределенными методами GetHashCode
и Equals
; этот класс key
будет определять способ группировки входных данных; keySelector
, который будет использоваться для создания ключей из входных данных; elementSelector
, который будет использоваться для выбора значений для соответствующие ключи.
Первый подход: использование анонимного типа в качестве ключа.
Мы можем использовать анонимный тип в качестве ключ для создания Lookup
. Anonymous types
автоматически реализует GetHashCode
и Equals
. Из MSDN:
Поскольку методы Equals и GetHashCode для анонимных типов определены в терминах методов Equals и GetHashCode свойств, два экземпляра одного и того же анонимного типа равны, только если все их свойства равно.
Вот как мы можем создать Lookup
, используя anonymous type
в качестве ключа:
var list = new List<ValueSetting>
{
new ValueSetting {param1 = 10, param2 = "foo", param3 = "abc", param4 = 500},
new ValueSetting {param1 = 20, param2 = "boo", param3 = "abc", param4 = 500},
new ValueSetting {param1 = 10, param2 = "foo", param3 = "abc", param4 = 600},
new ValueSetting {param1 = 20, param2 = "boo", param3 = "abc", param4 = 600},
new ValueSetting {param1 = 30, param2 = "foo", param3 = "abc", param4 = 500},
};
var lookup = list.ToLookup(
vs => new {vs.param1, vs.param2, vs.param3}, // Group key.
vs => vs.param4); // Group values.
foreach (var item in lookup)
{
Console.WriteLine("{0} => ({1})", item.Key, string.Join(", ", item.Select(i => i)));
}
Этот подход удобен, если вы собираетесь использовать Lookup
в одном методе, поскольку объекты анонимного типа не могут быть возвращены из метода и переданы другому методу в качестве аргумента.
Второй подход: введение класса ключей.
Другой подход заключается в определении класса, который будет использоваться в качестве ключа группирования. В этом классе мы должны переопределить методы GetHashCode
и Equals
. Если вы используете Visual Studio 2015 или более позднюю версию, вы можете автоматически сгенерировать эти элементы . Вот как мы можем определить такой класс:
public class Key
{
public int param1;
public string param2;
public string param3;
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
Key other = (Key) obj;
Key other = (Key) obj;
return param1 == other.param1 &&
string.Equals(param2, other.param2) &&
string.Equals(param3, other.param3);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = param1;
hashCode = (hashCode * 397) ^ (param2 != null ? param2.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (param3 != null ? param3.GetHashCode() : 0);
return hashCode;
}
}
}
И затем, используя этот ключевой класс, мы можем создать Lookup
:
var list = new List<ValueSetting>
{
new ValueSetting {param1 = 10, param2 = "foo", param3 = "abc", param4 = 500},
new ValueSetting {param1 = 20, param2 = "boo", param3 = "abc", param4 = 500},
new ValueSetting {param1 = 10, param2 = "foo", param3 = "abc", param4 = 600},
new ValueSetting {param1 = 20, param2 = "boo", param3 = "abc", param4 = 600},
new ValueSetting {param1 = 30, param2 = "foo", param3 = "abc", param4 = 500},
};
ILookup<Key, int> lookup = list.ToLookup(
vs => new Key {param1 = vs.param1, param2 = vs.param2, param3 = vs.param3}, // Group key.
vs => vs.param4); // Group values.
foreach (IGrouping<Key, int> item in lookup)
{
Console.WriteLine("{0}, {1}, {2} => ({3})",
item.Key.param1, item.Key.param2, item.Key.param3,
string.Join(", ", item.Select(i => i)));
}
Этот подход можно использовать, если вы хотите вернуть Lookup
из метода, или передать его в качестве аргумента другому методу, или сохранить как свойство класса (и в других случаях при создании Lookup
необходимо использовать вне метода, в котором он был создан) .