0

I have the following class

public class PaymentItemViewModel
    {
        public List<int> Placements { get; set; }

        public int StandardPayment { get; set; }

    }

Then a function returns the following

IEnumerable<PaymentItemViewModel> paymentItems

How can I get a list of all the Placements Ids, using LINQ?

Can i do something like the following?

List<int> placementIds = paymentItems.Any(x=>x.Placements) ??
user2206329
  • 2,792
  • 10
  • 54
  • 81

4 Answers4

3

Probably you are looking for Enumerable.SelectMany method

List<int> placementIds = paymentItems.SelectMany(vm => vm.Placements).ToList()
hazzik
  • 13,019
  • 9
  • 47
  • 86
  • thanks... just for my knowledge using LINQ, as opposed to using loops to get the placementIds, is there a performance difference? – user2206329 Oct 10 '13 at 03:24
  • 1
    It seems that in this case SelectMany would be about 10 times slower than version with AddRange and 3 times slower than nested foreach – hazzik Oct 10 '13 at 03:52
  • @hazzik a bit shocking. care to conjecture why ? are you sure it's not some sort of cache issue in your test rig? my guess: it has to do with the informalness of SelectMany, SelectMany has to infer a lot of stuf before beginning it's trip down the creating the results lane. When you say foreach, you are giving some serious intelligence to the process, that it is known that this traversal method will reach all depths necessary. – Andyz Smith Oct 10 '13 at 17:04
  • @AndyzSmith I think it SelectMany just slower in general as proportions stay the same with different numbers of items. Of course I can not always use nested foreach/foreach+AddRange, for example in lazy computations. – hazzik Oct 10 '13 at 19:28
2

You can do this:

var placementIds = new List<int>();

foreach(var item in paymentItems)
{
    foreach(var placementId in item.Placements)
    {
        placementIds.Add(placementId);
    }
}

If you really want to do it in LINQ, then you can do this:

var placementIds = paymentItems.SelectMany(item => item.Placements).ToList();
Karl Anderson
  • 34,606
  • 12
  • 65
  • 80
2

This should work. Any() just sees if any exist, and takes a boolean. SelectMany grabs all of a property or object "and flattens the resulting sequences into one sequence".

List<int> placementIds = paymentItems.SelectMany(x=>x.Placements).ToList();
Harrison
  • 3,843
  • 7
  • 22
  • 49
ps2goat
  • 8,067
  • 1
  • 35
  • 68
0

from aPaymentModelView in PaymentItems
from aPlacements in aPaymentmodelView
select aPlacements

this should work according to this

Flatten List in LINQ

EDIT

nicely provided by hazzik

var ids1 = (from model in models from placement in model.Placements select placement).ToList();

i guess i don't understand how it knows to concatenate the List<int> s

if i select placement, and then ToList, i should get a List<List<int>>

EDIT 2 ok, so actaully the cross join

from aModel in Models from aPlacement in aModel.Placements

produces a tuple of { Model, Placements } but these tuples are implicity concatenated with each other and all you have to do is to exclude the outer label, the Model

EDIT 3 i suppose it cannot be considered a cross join, although it feels like one, but since the placements are already segregated into separate lists, it is really just a full breadth and depth tree traversal,

Which could only be accurately described by a M-soft-ism, SelectMany

i am getting this idea from the type reported by ToString for the var. It has type of SelectMany iterator.

Community
  • 1
  • 1
Andyz Smith
  • 698
  • 5
  • 20