Вопрос по .net, c# – ToLookup с несколькими ключами

12

Есть ли способ требовать несколько ключей для.ToLookup функция, предоставляемая LINQ?

Я признаю, что на первый взгляд это кажется не интуитивным, и я ожидаю, что нет никакого реального способа сделать это, но я надеюсь, что кто-то знает способ.

Я в основном хочу иметь возможность поиска по двум значениям, напримерstring иintи получить объект с этими двумя значениями.

Example
    public class MyClass {
      public string StringProp {get;set;}
      public int IntProp {get;set;}
      public object MoreData {get;set;}
    }

    public class Main {
      public void Main() {
        HashSet<MyClass> set = new HashSet<MyClass>();
        set.Add(new MyClass {StringProp = "a", IntProp = 1, MoreData = null});
        set.Add(new MyClass {StringProp = "c", IntProp = 4, MoreData = new object()});
        set.Add(new MyClass {StringProp = "a", IntProp = 2, MoreData = "upupdowndown"});
        set.Add(new MyClass {StringProp = "c", IntProp = 1, MoreData = string.Empty});
        set.Add(new MyClass {StringProp = "c", IntProp = 4, MoreData = string.Empty});
        // Using 'var' because I don't know how this would be defined.
        // I recognize that this will not compile - but this is what I'm trying to do.
        var lookup = set.ToLookup(x => x.StringProp && x.IntProp)
        MyClass c = lookup["a", 1].First(); // Should return the first element
        IEnumerable<MyClass> list = lookup["c", 4]; // Should return the 2nd and last elements
      }
    }

Ваш Ответ

3   ответа
4

Хотя не то, что вы действительно хотите, но сделаете работу просто отлично

var r = set.ToLookup(x => new { x.StringProp, x.IntProp });
var f = r[ new { StringProp = "a", IntProp = 1 } ].First();
7

Таким образом, другие ответы совпадают с тем, о котором я думал, но несколько громоздким является создание кортежа или анонимного класса каждый раз, когда вы хотите просто получить значение из поиска. Было бы замечательно, если бы вы могли просто вставить строку и int в индексатор, чтобы получить значение. Создав свой собственный класс, чтобы обернуть поиск индексатором, вы можете сделать именно это.

public class MyLookup<T1, T2, TOut>
{
    private ILookup<Tuple<T1, T2>, TOut> lookup;
    public MyLookup(IEnumerable<TOut> source, Func<TOut, Tuple<T1, T2>> keySelector)
    {
        lookup = source.ToLookup(keySelector);
    }

    public IEnumerable<TOut> this[T1 first, T2 second]
    {
        get
        {
            return lookup[Tuple.Create(first, second)];
        }
    }

    //feel free to either expose the lookup directly, or add other methods to access the lookup
}

Вот пример его использования:

IEnumerable<MyClass> data = null; //TODO populate with real data
var lookup = new MyLookup<string, int, MyClass>(data
    , item => Tuple.Create(item.StringProp, item.IntProp));

IEnumerable<MyClass> someValue = lookup["c", 4];
Это действительно хорошая идея, но я пометил ответ Гейба как правильный, поскольку уже сделал достаточно абстракций, чтобы скрыть код, стоящий за повседневной разработкой. Merwer
Что ж, если я собираюсь добавить класс для абстрагирования нескольких ключей в поиске, я реализую его полностью:ILookup, ToLookupпредоставить версии для более чем 2 ключей, документировать их и т. д. Это немного больше работы.
Это несколько громоздко, но это то, что я бы реализовал, если бы мне приходилось часто делать подобные вещи.
@Gabe Согласен. (предел символа)
@Gabe TheMyLookup Класс уже реализован, поэтому для создания каждого его экземпляра требуется не больше работы, чем для вашего решения, и фактически используется результирующий & quot; lookup & quot; значительно проще Стоило ли время написать «MyLookup»? это хороший вопрос, но, учитывая, что это уже сделано, гораздо проще ответить на вопрос, использовать ли его.
20

я хотел бы использоватьTupleдля такого рода вещей:

var lookup = set.ToLookup(x => Tuple.Create(x.StringProp, x.IntProp));
MyClass c = lookup[Tuple.Create("a", 1)].First();
IEnumerable<MyClass> list = lookup[Tuple.Create("c", 4)];
Я не вижу, как это помогает.
Спасибо, Гейб. Я собираюсь попробовать это немного и рассказать вам, как это работает. Merwer

Похожие вопросы