【发布时间】:2012-12-30 01:02:14
【问题描述】:
在Tuples 的List 中创建一个列表(例如,每个Tuple 的第一项)的正确方法是什么?
如果我有一个List<Tuple<string,string>>,我如何获得每个Tuple 中第一个字符串的List<string>?
【问题讨论】:
在Tuples 的List 中创建一个列表(例如,每个Tuple 的第一项)的正确方法是什么?
如果我有一个List<Tuple<string,string>>,我如何获得每个Tuple 中第一个字符串的List<string>?
【问题讨论】:
List<string> list = tuples.Select(t => t.Item1).ToList();
或者,内存成本可能更低:
List<string> list = new List<String>(tuples.Count);
list.AddRange(tuples.Select(t => t.Item1));
因为它避免了List.Add在ToList中的加倍算法。
【讨论】:
ToList 或ToArray 过于慷慨。当序列很大时,您可以使用第二种方法避免OutOfMemoryExceptions。它可以保护高达 50% 的内存。我永远不会忘记它:stackoverflow.com/questions/10519275/…
IEnumerable 可以转换为ICollection 时才有效,上述情况并非如此。因此ToList 使用List.Add(有或没有构造函数)枚举整个序列。
一点 Linq 就可以解决问题:
var myStringList = myTupleList.Select(t=>t.Item1).ToList();
作为解释,由于 Tim 发布了几乎相同的答案,因此 Select() 创建了一个 1:1 的“投影”;它接受 Enumerable 的每个输入元素,并为每个输入元素计算 lambda 表达式并将结果作为具有相同数量元素的新 Enumerable 的元素返回。然后 ToList() 将遍历 Select() 生成的 Enumerable,并将每个元素一次添加到一个新的 List<T> 实例中。
Tim 对内存效率有很好的看法; ToList() 将创建一个列表并一次添加一个元素,这将导致 List 不断调整其底层数组的大小,每次将其加倍以确保其具有适当的容量。对于一个大列表,这可能会导致 OutOfMemoryExceptions,并且它将导致 CLR 为列表分配比必要更多的内存,除非元素的数量恰好是 2 的幂。
【讨论】:
如果您有List<Tuple<string, string>> listoftuples,您可以使用 List 的 Select 方法实现从每个 Tuple 中获取第一个字符串。
看起来像这样:
List<string> firstelements = listoftuples.Select(t => t.Item1).ToList();
【讨论】:
List<T>的方法;它是 System.Linq 库的一部分。
Select 是Enumerable<T> 中定义的扩展方法,适用于所有实现IEnumerable<T> - List<T> 在这种情况下没什么特别的。
通用变体: 用于选择集合元组长度未知的特定项目,即 2,3,4 ...:
static IEnumerable TupleListSelectQuery<T>(IEnumerable<T> lst, int index) where T : IStructuralEquatable, IStructuralComparable, IComparable
{
return lst.Select(t => typeof(T).GetProperty("Item" + Convert.ToString(itemNumber)).GetValue(t)).ToList();
}
index 的值对应于元组的枚举方式,即 1,2,3 ...(不是 0,1,2...)。
【讨论】: