c#将3个集合列表合并到一个列表中

时间:2012-10-22 16:37:18

标签: c# .net linq

我有3个收集清单如下。

public static List<Thing> English = new List<Thing>
{
    new Thing {ID = 1, Stuff = "one"},
    new Thing {ID = 2, Stuff = "two"},
    new Thing {ID = 3, Stuff = "three"}
};

public static List<Thing> Spanish = new List<Thing>
{
    new Thing {ID = 1, Stuff = "uno"},
    new Thing {ID = 2, Stuff = "dos"},
    new Thing {ID = 3, Stuff = "tres"},
    new Thing {ID = 4, Stuff = "cuatro"}
};

public static List<Thing> German = new List<Thing>
{
    new Thing {ID = 1, Stuff = "eins"},
    new Thing {ID = 2, Stuff = "zwei"},
    new Thing {ID = 3, Stuff = "drei"}
};

在运行时期间,列表的长度可能会有所不同。例如,德语可能有5个值,英语有2个,西班牙语有1个。

我需要找到哪个列表具有最大值,并且需要以下面的格式获得输出。

      Id English  German  Spanish
       1  one      eins    uno
       2  two      zwei    dos
       3  three    drei    tres
       4                   cuatro

你能帮我解决一下吗?

3 个答案:

答案 0 :(得分:6)

试试这个:

English.Select(t => new Tuple<Thing,int>(t, 1)).Concatenate(
    German.Select(t => new Tuple<Thing,int>(t, 2)).Concatenate(
        Spanish.Select(t => new Tuple<Thing,int>(t, 3))
    )
).GroupBy(p => p.Item1.ID)
.Select(g => new {
    Id = g.Key
,   English = g.Where(t => t.Item2==1).Select(t => t.Item2.Stuff).SingleOrDefault()
,   German = g.Where(t => t.Item2==2).Select(t => t.Item2.Stuff).SingleOrDefault()
,   Spanish = g.Where(t => t.Item2==3).Select(t => t.Item2.Stuff).SingleOrDefault()
});

我们的想法是使用其收藏来源标记原始项目(英语为1,德语为2,西班牙语为3,按ID对其进行分组,然后拉出使用我们在第一步中添加的标记的各种语言的详细信息。

答案 1 :(得分:1)

如果它们都从一个开始并且从不跳过任何数字(但可以在任何时候结束)那么你可以使用更简单的方法,例如:

int count = Math.Max(English.Count, Math.Max(Spanish.Count, German.Count));
var query = Enumerable.Range(0, count)
    .Select(num => new
    {
        Id = num + 1,
        English = GetValue(English, num),
        Spanish = GetValue(Spanish, num),
        German = GetValue(German, num),
    });

如果可以跳过数字,或者不从1开始,那么你可以使用这种稍微复杂的方法:

var englishDic = English.ToDictionary(thing => thing.ID, thing => thing.Stuff);
var spanishDic = Spanish.ToDictionary(thing => thing.ID, thing => thing.Stuff);
var germanDic = German.ToDictionary(thing => thing.ID, thing => thing.Stuff);

var query = englishDic.Keys
        .Union(spanishDic.Keys)
        .Union(germanDic.Keys)
        .Select(key => new
        {
            Id = key,
            English = GetValue(englishDic, key),
            Spanish = GetValue(spanishDic, key),
            German = GetValue(germanDic, key),
        });

需要一些辅助函数来避免无效的参数错误:

public static string GetValue(Dictionary<int, string> dictionary, int key)
{
    string output;
    if (dictionary.TryGetValue(key, out output))
        return output;
    else
        return "";
}

public static string GetValue(List<Thing> list, int index)
{
    if (index < list.Count)
        return list[index].Stuff;
    else
        return "";
}

答案 2 :(得分:0)

这很有趣:)

我这样做了,但是,就像许多这些答案一样,效率不高:

public IEnumerable ListEmAll() {
    return new List<int>() // just for balance, start with empty list
        .Union( English.Select(o => o.ID) )
        .Union( Spanish.Select(o => o.ID) )
        .Union( German.Select(o => o.ID) )
        .OrderBy(id => id)
        .Select(id =>
            new
            {
                ID = id,
                English = English.Where(o => o.ID == id).Select(o => o.Stuff),
                Spanish = Spanish.Where(o => o.ID == id).Select(o => o.Stuff),
                German = German.Where(o => o.ID == id).Select(o => o.Stuff)
            });
}

但我更喜欢的是不使用Linq,并返回一个复合词典......列表上没有昂贵的查找。

// keep a list of the languages for later
static Dictionary<string, List<Thing>> languages = new Dictionary<string, List<Thing>>(){
    {"English", English},
    {"Spanish", Spanish},
    {"German", German}
};

// result[3]["English"] = "three"
public Dictionary<int, Dictionary<string, string>> ListEmAll_better() {
    Dictionary<int, Dictionary<string, string>> result = new Dictionary<int, Dictionary<string, string>>();
    foreach(var lang in languages.Keys) {
        foreach(var thing in languages[lang]) {
            if(!result.ContainsKey(thing.ID)) {
                result[thing.ID] = new Dictionary<string, string>();
            }
            result[thing.ID][lang] = thing.Stuff;
        }
    }
    return result;
}