If they all start with one and never miss any numbers (but can end at any point), you can use a simpler approach, for example:
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), });
If it is possible for numbers to be skipped or not starting with one, you could use this slightly more complex approach:
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), });
To prevent erroneous argument errors, several auxiliary functions were required:
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 ""; }