使用LINQ简化foreach循环(在每次迭代中选择两个对象)

时间:2017-08-30 12:48:11

标签: c# linq

给出以下接口和两个类:

public static void main(String[] args) {

    for(int i=0;i<10;i++){
        for(int k=0;k<i;k++){
            System.out.print("*");
        }
        System.out.println();
    }
}

并给出了使用它们的以下逻辑:

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}";
}

测试通过了,我在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); 里面看到了我想要的内容 - 每个数字有两个对象实例:

list

我的问题是,如何使用LINQ简化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} 循环逻辑?我想也许可能有一种优雅的方式与SelectMany运算符一样,但我无法生成相同的输出。

2 个答案:

答案 0 :(得分:15)

SelectMany确实是你想要的:

var list = numbers.SelectMany(n => new IMyObj[] { new MyObj1(n), new MyObj2(n) })
                  .ToList();

换句话说,对于每个数字,创建一个双元素数组,然后使用SelectMany展平。

new IMyObj[]部分是必需的而不仅仅是new[],因为类型推断无法说明您想要的数组类型。如果类型相同,您可以执行以下操作:

var list = numbers.SelectMany(n => new[] { new MyObj(n), new MyObj(n) })
                  .ToList();

答案 1 :(得分:0)

您可以使用[Union][1]连接两个列表:

var result = numbers.Select(x => (IMyObj) new MyObj1(x))
    .Union(numbers.Select(x => x => new MyObj2(x)));

另外一个接一个地:

var l1 = numbers.Select(x => new MyObj1(x)).Cast<IMyObject>().ToList();
var l2 = numbers.Select(x => new MyObj(x));

var result = l1.Concat(l2);

l1.AddRange(l2)

当然,所有这些方法都不会与您的inout具有相同的顺序,因为首先存储MyObj1之外的所有实例,然后存储MyOb2的所有实例。