Given the following interface and two classes:
public interface IMyObj
{
int Id { get; set; }
}
public class MyObj1 : IMyObj
{
public MyObj1(int id) { Id = id; }
public int Id { get; set; }
public override string ToString() => $"{GetType().Name} : {Id}";
}
public class MyObj2 : IMyObj
{
public MyObj2(int id) { Id = id; }
public int Id { get; set; }
public override string ToString() => $"{GetType().Name} : {Id}";
}
And given following logic that uses them:
var numbers = new[] { 1, 5, 11, 17 };
var list = new List<IMyObj>();
foreach (var n in numbers)
{
// I'd like to simplify this part with LINQ...
list.Add(new MyObj1(n));
list.Add(new MyObj2(n));
}
Assert.AreEqual(8, list.Count);
The test passes, and I see inside list
exactly what I want - two object instances per a number:
Count = 8
[0]: {MyObj1 : 1}
[1]: {MyObj2 : 1}
[2]: {MyObj1 : 5}
[3]: {MyObj2 : 5}
[4]: {MyObj1 : 11}
[5]: {MyObj2 : 11}
[6]: {MyObj1 : 17}
[7]: {MyObj2 : 17}
My question is, how do I simplify the foreach
loop logic with LINQ? I'm thinking there might be an elegant way in doing the same with the SelectMany
operator perhaps, but I've not been able to produce the same output.
SelectMany
is indeed what you want:
var list = numbers.SelectMany(n => new IMyObj[] { new MyObj1(n), new MyObj2(n) })
.ToList();
In other words, for each number, create a two-element array, which is then flattened using to SelectMany
.
The new IMyObj[]
part is required rather than just new[]
because type inference can't tell what array type you'd want. If the types were the same, you could do something like:
var list = numbers.SelectMany(n => new[] { new MyObj(n), new MyObj(n) })
.ToList();
See more on this question at Stackoverflow