当我有一个清单时
IList<int> list = new List<int>();
list.Add(100);
list.Add(200);
list.Add(300);
list.Add(400);
list.Add(500);
提取对的方法是什么
Example : List elements {100,200,300,400,500}
Expected Pair : { {100,200} ,{200,300} ,{300,400} ,{400,500} }
使用 LINQ 最优雅的方式:
list.Zip(list.Skip(1), Tuple.Create)
现实生活中的示例:此扩展方法采用点集合 (
Vector2
) 并生成“连接点”所需的线集合 (PathSegment
)。
static IEnumerable<PathSegment> JoinTheDots(this IEnumerable<Vector2> dots)
{
var segments = dots.Zip(dots.Skip(1), (a,b) => new PathSegment(a, b));
return segments;
}
这将为您提供一个匿名“pair”对象数组,其中 A 和 B 属性对应于pair 元素。
var pairs = list.Where( (e,i) => i < list.Count - 1 )
.Select( (e,i) => new { A = e, B = list[i+1] } );
(e,i)
表示法表示同时采用元素和元素索引的签名。 Where
子句允许序列中除最后一个元素之外的所有元素。 Select
子句创建一个新的匿名对象,其中 A
元素分配了序列中的原始元素,而 B
元素分配了序列中的后续元素。也就是说,如果 e
代表每次迭代时的第 i
个元素,则 B
获取第 i+1
个元素。
您可以使用 for 循环:
var pairs = new List<int[]>();
for(int i = 0; i < list.Length - 1; i++)
pairs.Add(new [] {list[i], list[i + 1]);
你也可以使用LINQ,但它更丑陋:
var pairs = list.Take(list.Count - 1).Select((n, i) => new [] { n, list[i + 1] });
编辑:你甚至可以在原始的
IEnumerable
上做到这一点,但它丑陋得多:
var count = list.Count();
var pairs = list
.SelectMany((n, i) => new [] { new { Index = i - 1, Value = n }, new { Index = i, Value = n } })
.Where(ivp => ivp.Index >= 0 && ivp.Index < count - 1) //We only want one copy of the first and last value
.GroupBy(ivp => ivp.Index, (i, ivps) => ivps.Select(ivp => ivp.Value));
更一般的是:
public static IEnumerable<TResult> Pairwise<TSource, TResult>(this IEnumerable<TSource> values, int count, Func<TSource[], TResult> pairCreator)
{
if (count < 1) throw new ArgumentOutOfRangeException("count");
if (values == null) throw new ArgumentNullException("values");
if (pairCreator == null) throw new ArgumentNullException("pairCreator");
int c = 0;
var data = new TSource[count];
foreach (var item in values)
{
if (c < count)
data[c++] = item;
if (c == count)
{
yield return pairCreator(data);
c = 0;
}
}
}
以下解决方案使用zip方法。压缩originalList和originalList.Skip(1),以便得到想要的结果。
var adjacents =
originalList.Zip(originalList.Skip(1),
(a,b) => new {N1 = a, N2 = b});
使用
MoreLINQ中的
.Windowed()
:
var source = new[] {100,200,300,400,500};
var result = source.Windowed(2).Select(x => Tuple.Create(x.First(),x.Last()));
我的想法完全未经测试:
public static T Pairwise<T>(this IEnumerable<T> list)
{
T last;
bool firstTime = true;
foreach(var item in list)
{
if(!firstTime)
return(Tuple.New(last, item));
else
firstTime = false;
last = item;
}
}