Linq to Objects - возвращает пары чисел из списка чисел
var nums = new[]{ 1, 2, 3, 4, 5, 6, 7};
var pairs = /* some linq magic here*/ ;
= > пары = {{1, 2}, {3, 4}, {5, 6}, {7, 0}}
Элементы pairs
должны быть либо двухэлементными списками, либо экземплярами некоторого анонимного класса с двумя полями, например new {First = 1, Second = 2}
.
Ответы
Ответ 1
Ни один из методов linq по умолчанию не может сделать это лениво и с одним сканированием. Завершение последовательности само по себе делает 2 сканирования и группировки не совсем ленивыми. Лучше всего реализовать его непосредственно:
public static IEnumerable<T[]> Partition<T>(this IEnumerable<T> sequence, int partitionSize) {
Contract.Requires(sequence != null)
Contract.Requires(partitionSize > 0)
var buffer = new T[partitionSize];
var n = 0;
foreach (var item in sequence) {
buffer[n] = item;
n += 1;
if (n == partitionSize) {
yield return buffer;
buffer = new T[partitionSize];
n = 0;
}
}
//partial leftovers
if (n > 0) yield return buffer;
}
Ответ 2
Попробуйте следующее:
int i = 0;
var pairs =
nums
.Select(n=>{Index = i++, Number=n})
.GroupBy(n=>n.Index/2)
.Select(g=>{First:g.First().Number, Second:g.Last().Number});
Ответ 3
Это может быть немного более общим, чем вам нужно - вы можете установить пользовательский itemsInGroup
:
int itemsInGroup = 2;
var pairs = nums.
Select((n, i) => new { GroupNumber = i / itemsInGroup, Number = n }).
GroupBy(n => n.GroupNumber).
Select(g => g.Select(n => n.Number).ToList()).
ToList();
EDIT:
Если вы хотите добавить нули (или некоторые другие номера), если последняя группа имеет другой размер:
int itemsInGroup = 2;
int valueToAppend = 0;
int numberOfItemsToAppend = itemsInGroup - nums.Count() % itemsInGroup;
var pairs = nums.
Concat(Enumerable.Repeat(valueToAppend, numExtraItems)).
Select((n, i) => new { GroupNumber = i / itemsInGroup, Number = n }).
GroupBy(n => n.GroupNumber).
Select(g => g.Select(n => n.Number).ToList()).
ToList();
Ответ 4
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7 };
var result = numbers.Zip(numbers.Skip(1).Concat(new int[] { 0 }), (x, y) => new
{
First = x,
Second = y
}).Where((item, index) => index % 2 == 0);
Ответ 5
(предупреждение: выглядит уродливо)
var pairs = x.Where((i, val) => i % 2 == 1)
.Zip(
x.Where((i, val) => i % 2 == 0),
(first, second) =>
new
{
First = first,
Second = second
})
.Concat(x.Count() % 2 == 1 ? new[]{
new
{
First = x.Last(),
Second = default(int)
}} : null);
Ответ 6
public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max)
{
return InSetsOf(source, max, false, default(T));
}
public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max, bool fill, T fillValue)
{
var toReturn = new List<T>(max);
foreach (var item in source)
{
toReturn.Add(item);
if (toReturn.Count == max)
{
yield return toReturn;
toReturn = new List<T>(max);
}
}
if (toReturn.Any())
{
if (fill)
{
toReturn.AddRange(Enumerable.Repeat(fillValue, max-toReturn.Count));
}
yield return toReturn;
}
}
использование:
var pairs = nums.InSetsOf(2, true, 0).ToArray();
Ответ 7
IList<int> numbers = new List<int> {1, 2, 3, 4, 5, 6, 7};
var grouped = numbers.GroupBy(num =>
{
if (numbers.IndexOf(num) % 2 == 0)
{
return numbers.IndexOf(num) + 1;
}
return numbers.IndexOf(num);
});
Если вам нужна последняя пара, заполненная нулем, вы можете просто добавить ее перед выполнением группировки, если listcount нечетна.
if (numbers.Count() % 2 == 1)
{
numbers.Add(0);
}
Другим подходом может быть:
var groupedIt = numbers
.Zip(numbers.Skip(1).Concat(new[]{0}), Tuple.Create)
.Where((x,i) => i % 2 == 0);
Или вы используете MoreLinq, у которого много полезных расширений:
IList<int> numbers = new List<int> {1, 2, 3, 4, 5, 6, 7};
var batched = numbers.Batch(2);
Ответ 8
var nums = new float[] { 1, 2, 3, 4, 5, 6, 7 };
var enumerable =
Enumerable
.Range(0, nums.Length)
.Where(i => i % 2 == 0)
.Select(i =>
new { F = nums[i], S = i == nums.Length - 1 ? 0 : nums[i + 1] });
Ответ 9
var w =
from ei in nums.Select((e, i) => new { e, i })
group ei.e by ei.i / 2 into g
select new { f = g.First(), s = g.Skip(1).FirstOrDefault() };
Ответ 10
Другой вариант - использовать метод SelectMany LINQ. Это больше для тех, кто хочет перебирать список элементов, и для каждого элемента возвращают 2 или более его свойств. Не нужно снова перебирать список для каждого свойства, только один раз.
var list = new [] {//Some list of objects with multiple properties};
//Select as many properties from each Item as required.
IEnumerable<string> flatList = list.SelectMany(i=> new[]{i.NameA,i.NameB,i.NameC});
Ответ 11
Еще одно простое решение с использованием index
и index + 1
.
var nums = Enumerable.Range(1, 10);
var pairs = nums.Select((item, index) =>
new { First = item, Second = nums.ElementAtOrDefault(index + 1) })
.SkipLastN(1);
pairs.ToList().ForEach(p => Console.WriteLine($"({p.First}, {p.Second}) "));
Последний элемент недействителен и должен быть удален с помощью SkipLastN()
.
Ответ 12
это дает все возможные пары (vb.net):
Dim nums() = {1, 2, 3, 4, 5, 6, 7}
Dim pairs = From a In nums, b In nums Where a <> b Select a, b
Edit:
Dim allpairs = From a In nums, b In nums Where b - a = 1 Select a, b
Dim uniquePairs = From p In allpairs Where p.a Mod 2 <> 0 Select p
Примечание: последняя пара отсутствует, работая над ней
Edit:
union uniquePairs
с парой {nums.Last,0}