Присоединяйтесь к двум заказанным коллекциям с LINQ - PullRequest
1 голос
/ 23 ноября 2011

У меня есть два типа данных, Foo и Bar, у которых есть свойство определять порядок:

class Foo
{
    public int Order { get; set; }
    public string FooValue { get; set; }
}

class Bar
{
    public int Order { get; set; }
    public string BarValue { get; set; }
}

Затем у меня есть две коллекции этих типов.Я хотел бы присоединиться к коллекциям, чтобы результат содержал пары Foo и Bar.Количество пар должно быть числом Bar элементов.

Каждая пара должна состоять из элемента Bar и самого «последнего» элемента Foo (с наибольшим значением Foo Order, ограниченным текущим значением Bar Order).

Например, для следующих коллекций (некоторые операторы опущены):

var foos = new [] { (1, "Foo1"), (2, "Foo2"), (5, "Foo5"), (7, "Foo7") };
var bars = new [] { (1, "Bar1"), (6, "Bar6") };

Результат будет:

result = { 
    ((1, "Bar1"), (1, "Foo1")),
    ((6, "Bar6"), (5, "Foo5"))
};

Как мне этого добиться с помощью LINQ и C # 4.0?

Ответы [ 3 ]

2 голосов
/ 23 ноября 2011

Если foos отсортировано по Order, вы можете сделать:

var fubars = from bar in bars
             let bestFoo = foos.TakeWhile(foo => foo.Order <= bar.Order)
                               .LastOrDefault()
             select new { Bar = bar, Foo = bestFoo };

В противном случае, я предлагаю сначала отсортировать foos.

Вы можете сделать этот запрос намного более эффективным, используя бинарный поиск (например, Array.BinarySearch) вместо линейного поиска, как в моем примере.

1 голос
/ 23 ноября 2011

Если вы разрешите foo повторений в тех случаях, когда граница foo одинакова для нескольких bar объектов:

var result = bars.Zip(foos, 
        (b,f) => Tuple.Create(b, foos.TakeWhile(foo => foo.Order <= b.Order).Last()));

Конечно, это все еще менее эффективно, чем итерация, так как TakeWhile будет вызываться для каждого bars объекта (начиная с начала каждый раз)

Что я подразумеваю под foo повторениями, так это для ввода, такого как

var foos = new [] { new Foo(1, "Foo1"), new Foo(3, "Foo3"), new Foo(5, "Foo5")};
var bars = new [] { new Bar(1, "Bar1"), new Bar(2, "Bar2") };

Результат будет

{ 
    ((1, "Bar1"), (1, "Foo1")),
    ((2, "Bar2"), (1, "Foo1")) //Foo1 again
};
0 голосов
/ 23 ноября 2011

Используя union () Linq, вы можете объединить 2 одинаковые упорядоченные коллекции элементов ...

...