TrueWill
TrueWill

Reputation: 25573

Create sequence consisting of multiple property values

I have an existing collection of objects with two properties of interest. Both properties are of the same type. I want to create a new sequence consisting of the property values. Here's one way (I'm using tuples instead of my custom type for simplicity):

var list = new List<Tuple<string, string>>
    { Tuple.Create("dog", "cat"), Tuple.Create("fish", "frog") };

var result =
    list.SelectMany(x => new[] {x.Item1, x.Item2});

foreach (string item in result)
{
    Console.WriteLine(item);
}

Results in:

dog
cat
fish
frog

This gives me the results I want, but is there a better way to accomplish this (in particular, without the need to create arrays or collections)?

Edit:

This also works, at the cost of iterating over the collection twice:

var result = list.Select(x => x.Item1).Concat(list.Select(x => x.Item2));

Upvotes: 2

Views: 163

Answers (2)

Razor
Razor

Reputation: 17518

If you want to avoid creating another collection, you could yield the results instead.

void Main()
{
    var list = new List<Tuple<string, string>>
        { Tuple.Create("dog", "cat"), Tuple.Create("fish", "frog") };

        foreach (var element in GetSingleList(list))
        {
            Console.WriteLine (element);
        }
}

// A reusable extension method would be a better approach.
IEnumerable<T> GetSingleList<T>(IEnumerable<Tuple<T,T>> list) {

    foreach (var element in list)
    {
        yield return element.Item1;
        yield return element.Item2;
    }

}

Upvotes: 2

Ahmad Mageed
Ahmad Mageed

Reputation: 96557

I think your approach is fine and I would stick with that. The use of the array nicely gets the job done when using SelectMany, and the final result is an IEnumerable<string>.

There are some alternate approaches, but I think they're more verbose than your approach.

Aggregate approach:

var result = list.Aggregate(new List<string>(), (seed, t) =>
{
    seed.Add(t.Item1);
    seed.Add(t.Item2);
    return seed;
});
result.ForEach(Console.WriteLine);

ForEach approach:

var result = new List<string>();
list.ForEach(t => { result.Add(t.Item1); result.Add(t.Item2); });
result.ForEach(Console.WriteLine);

In both cases a new List<string> is created.

Upvotes: 2

Related Questions