Flatten a Collection with LINQ ?

  • Thread starter Thread starter sloan
  • Start date Start date
S

sloan

I'm trying to get a "flat list" of values.

Below is the sample.

Desired Results:

Bobbie Brady has these toys : TeddyBear,Wagon,TonkaTruck
Cindy Brady has these toys : Dollie,TeaSet,Insta-Bake

Some kind of delimiter between the toys would be nice (comma above).

All code below, I'm just missing the magically LINQ statement.

THANKS!




public class Kid

{

public Kid(string firstName, string lastName)

{

this.FirstName = firstName;

this.LastName = lastName;

this.FavoriteToys = new ToyCollection();

}

public string FirstName { get; set; }

public string LastName { get; set; }

public ToyCollection FavoriteToys { get; set; }

}

public class Toy

{

public Toy(string name) { this.ToyName = name; }

public string ToyName { get; set; }

}

public class KidCollection : List<Kid>{}

public class ToyCollection : List<Toy>{}



static void Main(string[] args)

{



KidCollection kc = new KidCollection();

kc.Add(new Kid("Bobbie", "Brady"));

kc.Add(new Kid("Cindy", "Brady"));

kc.Add(new Kid("Danny", "Partridge"));

kc[0].FavoriteToys.Add(new Toy("TeddyBear"));

kc[0].FavoriteToys.Add(new Toy("Wagon"));

kc[0].FavoriteToys.Add(new Toy("TonkaTruck"));

kc[1].FavoriteToys.Add(new Toy("Dollie"));

kc[1].FavoriteToys.Add(new Toy("TeaSet"));

kc[1].FavoriteToys.Add(new Toy("Insta-Bake"));

kc[2].FavoriteToys.Add(new Toy("Drums"));

kc[2].FavoriteToys.Add(new Toy("DrumLessons"));

kc[2].FavoriteToys.Add(new Toy("MoreDrumLessons"));



var v = from k in kc

where k.LastName.Contains("Brady")

orderby k.FirstName descending

select k.FirstName + " " + k.LastName + " has these toys : " +
k.FavoriteToys.SelectMany(l => l.ToyName).ToList();



foreach (string s in v)

Console.WriteLine(s);





}
 
sloan said:
I'm trying to get a "flat list" of values.

Below is the sample.

Desired Results:

Bobbie Brady has these toys : TeddyBear,Wagon,TonkaTruck
Cindy Brady has these toys : Dollie,TeaSet,Insta-Bake

Some kind of delimiter between the toys would be nice (comma above).

var v = from k in kc

where k.LastName.Contains("Brady")

orderby k.FirstName

select k.FirstName + " " + k.LastName + " has these
toys : " +
k.FavoriteToys.Select(l => l.ToyName).Aggregate(new
StringBuilder(), (sb, s) => sb.Append(s + ", "), sb => {
sb.Remove(sb.Length - 2, 2); return sb.ToString(); });


does that but is a bit ugly in my view (in particular that bit stripping
the last ", ").
 
Thanks Martin.

When googling (errr:: binging)....I kept finding "Use SelectMany" comments.
I'll have to do some research into Aggregate.

My linq skills are subpar right now. :<
 
sloan said:
When googling (errr:: binging)....I kept finding "Use SelectMany" comments.

SelectMany helps if you have a collection of collections and want to
flatten that. For instance if you take your KidCollection kc and use
kc.Select(k => k.FavoriteToys)
then you get a collection of collections (IEnumerable<ToyCollection>).
If you use
kc.SelectMany(k = k.FavoriteToys)
instead then you have a flat collection of Toys (IEnumerable<Toy>).
 
sloan said:
I'm trying to get a "flat list" of values.

Below is the sample.

Desired Results:

Bobbie Brady has these toys : TeddyBear,Wagon,TonkaTruck
Cindy Brady has these toys : Dollie,TeaSet,Insta-Bake

Some kind of delimiter between the toys would be nice (comma above).
All code below, I'm just missing the magically LINQ statement.
var v = from k in kc
where k.LastName.Contains("Brady")
orderby k.FirstName descending
select k.FirstName + " " + k.LastName + " has these toys : " +
k.FavoriteToys.SelectMany(l => l.ToyName).ToList();

Looks like you don't actually need sexy linq-magic here
but a simple string.Join and kind of a subselect
will suffice for a In-Memory query

var v = from k in kc
where k.LastName == "Brady"
orderby k.FirstName descending
select k.FirstName + " " + k.LastName
+ " has these toys: " + string.Join (
"," ,
(from t in k.FavoriteToys select t.ToyName).ToArray()
);


SelectMany would be useful if you wouldn't need to keep the
relation between Toy and Owner, but simply wanted a completely
flattened list of all toys of all children, iirc

hth
Christoph
 
Christoph said:
sloan schrieb:>
Looks like you don't actually need sexy linq-magic here
but a simple string.Join and kind of a subselect
will suffice for a In-Memory query

var v = [...]
+ " has these toys: " + string.Join (
"," ,
where

(from t in k.FavoriteToys select t.ToyName).ToArray()
);

should be condensed to:

+ string.Join(",", k.FavoriteToys.Select(t=>t.ToyName).ToArray());

to look a bit more like black LINQish magic

Christoph
 
Back
Top