Group items by total amount - c#

Suppose I have this number list:
List<int> nu = new List<int>();
nu.Add(2);
nu.Add(1);
nu.Add(3);
nu.Add(5);
nu.Add(2);
nu.Add(1);
nu.Add(1);
nu.Add(3);
Keeping the list items in the same order, is it possible to group the items in linq that are sum of 6 so results would be something like this:
2,1,3 - 5 - 2,1,1 - 3

Solving this with LINQ directly would be bothersome, instead you could make an extension method:
// Assumptions:
// (1) All non-negative, or at least you don't mind them in your sum
// (2) Items greater than the sum are returned by their lonesome
static IEnumerable<IEnumerable<int>> GroupBySum(this IEnumerable<int> source,
int sum)
{
var running = 0;
var items = new List<int>();
foreach (var x in source)
{
if (running + x > sum && items.Any())
{
yield return items;
items = new List<int>();
running = 0;
}
running += x;
items.Add(x);
}
if (items.Any()) yield return items;
}

You could do it with Aggregate.
(Side note: Use LinqPad to test/write these types of queries, makes it easy)
Gives these results:
Like this:
class Less7Holder
{
public List<int> g = new List<int>();
public int mySum = 0;
}
void Main()
{
List<int> nu = new List<int>();
nu.Add(2);
nu.Add(1);
nu.Add(3);
nu.Add(5);
nu.Add(2);
nu.Add(1);
nu.Add(1);
nu.Add(3);
var result = nu .Aggregate(
new LinkedList<Less7Holder>(),
(holder,inItem) =>
{
if ((holder.Last == null) || (holder.Last.Value.mySum + inItem >= 7))
{
Less7Holder t = new Less7Holder();
t.g.Add(inItem);
t.mySum = inItem;
holder.AddLast(t);
}
else
{
holder.Last.Value.g.Add(inItem);
holder.Last.Value.mySum += inItem;
}
return holder;
},
(holder) => { return holder.Select((h) => h.g );} );
result.Dump();
}

Related

Mapping a list of ints into a list of MinMax ranges with LINQ [duplicate]

When i have a list
IList<int> list = new List<int>();
list.Add(100);
list.Add(200);
list.Add(300);
list.Add(400);
list.Add(500);
What is the way to extract a pairs
Example : List elements {100,200,300,400,500}
Expected Pair : { {100,200} ,{200,300} ,{300,400} ,{400,500} }
The most elegant way with LINQ: list.Zip(list.Skip(1), Tuple.Create)
A real-life example: This extension method takes a collection of points (Vector2) and produces a collection of lines (PathSegment) needed to 'join the dots'.
static IEnumerable<PathSegment> JoinTheDots(this IEnumerable<Vector2> dots)
{
var segments = dots.Zip(dots.Skip(1), (a,b) => new PathSegment(a, b));
return segments;
}
This will give you an array of anonymous "pair" objects with A and B properties corresponding to the pair elements.
var pairs = list.Where( (e,i) => i < list.Count - 1 )
.Select( (e,i) => new { A = e, B = list[i+1] } );
You can use a for loop:
var pairs = new List<int[]>();
for(int i = 0; i < list.Length - 1; i++)
pairs.Add(new [] {list[i], list[i + 1]);
You can also use LINQ, but it's uglier:
var pairs = list.Take(list.Count - 1).Select((n, i) => new [] { n, list[i + 1] });
EDIT: You can even do it on a raw IEnumerable, but it's much uglier:
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));
More general would be:
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;
}
}
}
Following solution uses zip method. Zip originalList and originalList.Skip(1) so that one gets desired result.
var adjacents =
originalList.Zip(originalList.Skip(1),
(a,b) => new {N1 = a, N2 = b});
Using .Windowed() from MoreLINQ:
var source = new[] {100,200,300,400,500};
var result = source.Windowed(2).Select(x => Tuple.Create(x.First(),x.Last()));
Off the top of my head and completely untested:
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;
}
}

How to remove duplicate list in List<List<int>>

I have List<List<int>>, For example
List<List<int>> has {{1,2,3}, {1,1,2,}, {1,2,3}}.
I want to remove duplicate in this:
Result should be: {{1,2,3}, {1,1,2}}
The problem is the inner lists are reference types so they have different object hashcode and hence are treated separate.
I don't want to iterate list completely to find duplicates as its not optimum.
Try this:
List<List<int>> lst = new List<List<int>>()
{
new List<int> {1,2,3},
new List<int> {1,1,2},
new List<int> {1,2,3}
};
var result = lst.GroupBy(c => String.Join(",", c)).Select(c => c.First().ToList()).ToList();
You can implement an EqualityComparer class and use it in Distinct method of LINQ.
public class CustomEqualityComparer : IEqualityComparer<List<int>>
{
public bool Equals(List<int> x, List<int> y)
{
if (x.Count != y.Count)
return false;
for (int i = 0; i < x.Count; i++)
{
if (x[i] != y[i])
return false;
}
return true;
}
public int GetHashCode(List<int> obj)
{
return 0;
}
}
and use it like this
public static void Main(string[] args)
{
var list = new List<List<int>>() { new List<int> { 1, 1, 2 }, new List<int> { 1, 2, 3 }, new List<int> { 1, 1, 2 } };
var res = list.Distinct(new CustomEqualityComparer());
Console.WriteLine("Press any key to continue.");
Console.ReadLine();
}
It's very simple:
List<List<int>> lst = new List<List<int>>()
{
new List<int> {1,2,3},
new List<int> {1,1,2,},
new List<int> {1,2,3},
};
var result =
lst
.Where((xs, n) =>
!lst
.Skip(n + 1)
.Any(ys => xs.SequenceEqual(ys)))
.ToList();
I get this result:
What you want is more complicated than simple comparision.
In my point of view you should create a new type / class like
IntegerCollection : ICollection
Then you should implement Equals in that way:
bool Equals(IntegerCollection col) { if(this.Count() != col.Count())
return false;
if(this.Sum() != col.Sum())
return false;
for(int i = 0; i < this.Count(); i++) {
if(this[i]==col[i]){
continue;
}else{
return false;
} }
return true; }
And finally
List<IntegerCollection> collections = new List<IntegerCollection> {
new IntegerCollection({1,2,3}),
new IntegerCollection({1,1,2}),
new IntegerCollection({1,2,3})};
var distincts = collections.Distinct();
Using #farid's CustomEqualityComparer you can also make use of HashSet:
List<List<int>> RemoveDuplicates(IEnumerable<List<int>> values)
{
return new HashSet<List<int>>(values,new CustomEqualityComparer()).ToList();
}

Combine entries from two lists by position using LINQ

Say I have two lists with following entries
List<int> a = new List<int> { 1, 2, 5, 10 };
List<int> b = new List<int> { 6, 20, 3 };
I want to create another List c where its entries are items inserted by position from two lists. So List c would contain the following entries:
List<int> c = {1, 6, 2, 20, 5, 3, 10}
Is there a way to do it in .NET using LINQ? I was looking at .Zip() LINQ extension, but wasn't sure how to use it in this case.
Thanks in advance!
To do it using LINQ, you can use this piece of LINQPad example code:
void Main()
{
List<int> a = new List<int> { 1, 2, 5, 10 };
List<int> b = new List<int> { 6, 20, 3 };
var result = Enumerable.Zip(a, b, (aElement, bElement) => new[] { aElement, bElement })
.SelectMany(ab => ab)
.Concat(a.Skip(Math.Min(a.Count, b.Count)))
.Concat(b.Skip(Math.Min(a.Count, b.Count)));
result.Dump();
}
Output:
This will:
Zip the two lists together (which will stop when either runs out of elements)
Producing an array containing the two elements (one from a, another from b)
Using SelectMany to "flatten" this out to one sequence of values
Concatenate in the remainder from either list (only one or neither of the two calls to Concat should add any elements)
Now, having said that, personally I would've used this:
public static IEnumerable<T> Intertwine<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
using (var enumerator1 = a.GetEnumerator())
using (var enumerator2 = b.GetEnumerator())
{
bool more1 = enumerator1.MoveNext();
bool more2 = enumerator2.MoveNext();
while (more1 && more2)
{
yield return enumerator1.Current;
yield return enumerator2.Current;
more1 = enumerator1.MoveNext();
more2 = enumerator2.MoveNext();
}
while (more1)
{
yield return enumerator1.Current;
more1 = enumerator1.MoveNext();
}
while (more2)
{
yield return enumerator2.Current;
more2 = enumerator2.MoveNext();
}
}
}
Reasons:
It doesn't enumerate a nor b more than once
I'm skeptical about the performance of Skip
It can work with any IEnumerable<T> and not just List<T>
I'd create an extension method to do it.
public static List<T> MergeAll<T>(this List<T> first, List<T> second)
{
int maxCount = (first.Count > second. Count) ? first.Count : second.Count;
var ret = new List<T>();
for (int i = 0; i < maxCount; i++)
{
if (first.Count < maxCount)
ret.Add(first[i]);
if (second.Count < maxCount)
ret.Add(second[i]);
}
return ret;
}
This would iterate through both lists once. If one list is bigger than the other it will continue to add until it's done.
You could try this code:
List<int> c = a.Select((i, index) => new Tuple<int, int>(i, index * 2))
.Union(b.Select((i, index) => new Tuple<int, int>(i, index * 2 + 1)))
.OrderBy(t => t.Second)
.Select(t => t.First).ToList();
It makes a union of two collections and then sorts that union using index. Elements from the first collection have even indices, from the second - odd ones.
Just wrote a little extension for this:
public static class MyEnumerable
{
public static IEnumerable<T> Smash<T>(this IEnumerable<T> one, IEnumerable<T> two)
{
using (IEnumerator<T> enumeratorOne = one.GetEnumerator(),
enumeratorTwo = two.GetEnumerator())
{
bool twoFinished = false;
while (enumeratorOne.MoveNext())
{
yield return enumeratorOne.Current;
if (!twoFinished && enumeratorTwo.MoveNext())
{
yield return enumeratorTwo.Current;
}
}
if (!twoFinished)
{
while (enumeratorTwo.MoveNext())
{
yield return enumeratorTwo.Current;
}
}
}
}
}
Usage:
var a = new List<int> { 1, 2, 5, 10 };
var b = new List<int> { 6, 20, 3 };
var c = a.Smash(b); // 1, 6, 2, 20, 5, 3, 10
var d = b.Smash(a); // 6, 1, 20, 2, 3, 5, 10
This will work for any IEnumerable so you can also do:
var a = new List<string> { "the", "brown", "jumped", "the", "lazy", "dog" };
var b = new List<string> { "quick", "dog", "over" };
var c = a.Smash(b); // the, quick, brown, fox, jumped, over, the, lazy, dog
You could use Concat and an anonymous type which you order by the index:
List<int> c = a
.Select((val, index) => new { val, index })
.Concat(b.Select((val, index) => new { val, index }))
.OrderBy(x => x.index)
.Select(x => x.val)
.ToList();
However, since that's not really elegant and also less efficient than:
c = new List<int>(a.Count + b.Count);
int max = Math.Max(a.Count, b.Count);
int aMax = a.Count;
int bMax = b.Count;
for (int i = 0; i < max; i++)
{
if(i < aMax)
c.Add(a[i]);
if(i < bMax)
c.Add(b[i]);
}
I wouldn't use LINQ at all.
Sorry for adding a third extension method inspired by the other two, but I like it shorter:
static IEnumerable<T> Intertwine<T>(this IEnumerable<T> a, IEnumerable<T> b)
{
using (var enumerator1 = a.GetEnumerator())
using (var enumerator2 = b.GetEnumerator()) {
bool more1 = true, more2 = true;
do {
if (more1 && (more1 = enumerator1.MoveNext()))
yield return enumerator1.Current;
if (more2 && (more2 = enumerator2.MoveNext()))
yield return enumerator2.Current;
} while (more1 || more2);
}
}

Lists permutations (unknown number) [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Combination of List<List<int>>
I have multiple Lists, could be 2 or 3 up to 10 lists, with multiple
values in them. Now what I need to do is to get a combination of all
of them.
For example, if I have 3 lists with the following values:
List 1: 3, 5, 7
List 2: 3, 5, 6
List 3: 2, 9
I would get these combinations
3,3,2
3,3,9
3,5,2
Etc..
Now the problem is I cannot do this easily because I do not know how many lists I have, therefore determine how many loops I need.
You could probably make that a lot easier, but this is what I had in mind just now:
List<List<int>> lists = new List<List<int>>();
lists.Add(new List<int>(new int[] { 3, 5, 7 }));
lists.Add(new List<int>(new int[] { 3, 5, 6 }));
lists.Add(new List<int>(new int[] { 2, 9 }));
int listCount = lists.Count;
List<int> indexes = new List<int>();
for (int i = 0; i < listCount; i++)
indexes.Add(0);
while (true)
{
// construct values
int[] values = new int[listCount];
for (int i = 0; i < listCount; i++)
values[i] = lists[i][indexes[i]];
Console.WriteLine(string.Join(" ", values));
// increment indexes
int incrementIndex = listCount - 1;
while (incrementIndex >= 0 && ++indexes[incrementIndex] >= lists[incrementIndex].Count)
{
indexes[incrementIndex] = 0;
incrementIndex--;
}
// break condition
if (incrementIndex < 0)
break;
}
If I’m not completely wrong, this should be O(Nm) with m being the number of lists and N the number of permutations (product of the lengths of all m lists).
you could make a List<List<yourValueType> mainlist in which you put all your lists.
then with a simple
int numberOfIterations = 1;
foreach(var item in mainlist)
{
numberOfIterations *= item.Count;
}
this would get the amount of iterations you would have to execute in total.
Non-recursive solution, works on any IEnumerables (not just lists) without solidifying them:
public static IEnumerable<IEnumerable<T>> Permutations<T>(
this IEnumerable<IEnumerable<T>> source)
{
// Check source non-null, non-empty?
var enumerables = source.ToArray();
Stack<IEnumerator<T>> fe = new Stack<IEnumerator<T>>();
fe.Push(enumerables[0].GetEnumerator());
while (fe.Count > 0)
{
if (fe.Peek().MoveNext())
{
if (fe.Count == enumerables.Length)
yield return new Stack<T>(fe.Select(e => e.Current));
else
fe.Push(enumerables[fe.Count].GetEnumerator());
}
else
{
fe.Pop().Dispose();
}
}
}
Not very efficient but very easy to understand approach might be to solve this task recursively. Consider a method which computes permutations for N lists. If you have such a method then you can easily compute permutations for N+1 lists by combining all permutation of N lists with every number in the last list. You should also handle corner case which permutations of 0 lists. Then implementation seems to be straightforward:
IEnumerable<IEnumerable<T>> GetAllPermutations<T>(IEnumerable<IEnumerable<T>> inputLists)
{
if (!inputLists.Any()) return new [] { Enumerable.Empty<T>() };
else
{
foreach (var perm in GetAllPermutations(inputLists.Skip(1)))
foreach (var x in inputLists.First())
yield return new[]{x}.Concat(perm);
}
}
As an alternative, following rawlings general idea the following should work
public static IEnumerable<IEnumerable<T>> Permutations<T> (this IEnumerable<IEnumerable<T>> underlying)
{
var enumerators = new Queue<IEnumerator<T>>(underlying.Select(u => u.GetEnumerator())
.Where(enumerator => enumerator.MoveNext());
Boolean streaming = enumerators.Any();
if(streaming)
{
IEnumerable<T> result;
IEnumerator<T> finalEnumerator = enumerators.Dequeue();
Func<Boolean,Boolean> finalAction = b => b ? b : finalEnumerator.MoveNext();
Func<Boolean,Boolean> interimAction =
enumerators.Reverse()
.Select(enumerator => new Func<Boolean,Boolean>(b => b ? b : (enumerator.MoveNext() ? true : enumerator.ResetMove())))
.Aggregate((f1,f2) => (b => f1(f2(b)));
enumerators.Enqueue(finalEnumerator);
Func<Boolean,Boolean> permutationAction =
interimAction == null ?
finalAction :
b => finalAction(interimAction(b));
while(streaming)
{
result = new Queue<T>(enumerators.Select(enumerator => enumerator.Current))
streaming = permutationAction(true);
yield return result;
}
}
private static Boolean ResetMove<T>(this IEnumerator<T> underlying)
{
underlying.Reset();
underlying.MoveNext();
return false;
}

Group a list into groups of 3 and select max of each group

I have a list of lists of dynamic which is currently being filtered through this:
var CPUdataIWant = from s in rawData
where s.stat.Contains("CPU")
select s;
//CPUDataIWant is a List<List<dynamic>>.
I have 86000 values in each inner list.
And what I need to do, is group the values into groups of 3, select the max of that group, and insert that into another list of List of dynamic, or just filter it out of CPUDataIWant.
So an example of what I want would be:
Raw data = 14,5,7,123,5,1,43,87,9
And my processed value would be:
ProceData = [14,5,7], [123,5,1], [43,87,9]
ProceData = [14,123,87]
Doesn't have to be using linq but the easier the better.
EDIT: Ok I explained what a wanted a bit poorly.
here's what I have:
List<List<object>>
In this List, I'll have X amount of Lists called A.
In A I'll have 86000 values, let's say they're ints for now.
What I'd like, is to have
List<List<object>>
But instead of 86000 values in A, I want 28700, which would be made from the max of every 3 values in A.
IEnumerable<int> filtered = raw.Select((x, i) => new { Index = i, Value = x }).
GroupBy(x => x.Index / 3).
Select(x => x.Max(v => v.Value));
or, if you plan to use it more often
public static IEnumerable<int> SelectMaxOfEvery(this IEnumerable<int> source, int n)
{
int i = 0;
int currentMax = 0;
foreach (int d in source)
{
if (i++ == 0)
currentMax = d;
else
currentMax = Math.Max(d, currentMax);
if (i == n)
{
i = 0;
yield return currentMax;
}
}
if (i > 0)
yield return currentMax;
}
//...
IEnumerable<int> filtered = raw.SelectMaxOfEvery(3);
Old-school way of doing things makes it quite simple (although it's not as compact as LINQ):
// Based on this spec: "CPUDataIWant is a List<List<dynamic>>"
// and on the example, which states that the contents are numbers.
//
List<List<dynamic>> filteredList = new List<List<dynamic>>();
foreach (List<dynamic> innerList in CPUDataIWant)
{
List<dynamic> innerFiltered = new List<dynamic>();
// if elements are not in multiples of 3, the last one or two won't be checked.
for (int i = 0; i < innerList.Count; i += 3)
{
if(innerList[i+1] > innerList[i])
if(innerList[i+2] > innerList[i+1])
innerFiltered.Add(innerList[i+2]);
else
innerFiltered.Add(innerList[i+1]);
else
innerFiltered.Add(innerList[i]);
}
filteredList.Add(innerFiltered);
}
This should give the desired result:
var data = new List<dynamic> { 1, 2, 3, 3, 10, 1, 5, 2, 8 };
var firsts = data.Where((x, i) => i % 3 == 0);
var seconds = data.Where((x, i) => (i + 2) % 3 == 0);
var thirds = data.Where((x, i) => (i + 1) % 3 == 0);
var list = firsts.Zip(
seconds.Zip(
thirds, (x, y) => Math.Max(x, y)
),
(x, y) => Math.Max(x, y)
).ToList();
List now contains:
3, 10, 8
Or generalized to an extension method:
public static IEnumerable<T> ReduceN<T>(this IEnumerable<T> values, Func<T, T, T> map, int N)
{
int counter = 0;
T previous = default(T);
foreach (T item in values)
{
counter++;
if (counter == 1)
{
previous = item;
}
else if (counter == N)
{
yield return map(previous, item);
counter = 0;
}
else
{
previous = map(previous, item);
}
}
if (counter != 0)
{
yield return previous;
}
}
Used like this:
data.ReduceN(Math.Max, 3).ToList()
If you felt a need to use Aggregate you could do it like this:
(tested wiht LinqPad)
class Holder
{
public dynamic max = null;
public int count = 0;
}
void Main()
{
var data = new List<dynamic>
{new { x = 1 }, new { x = 2 }, new { x = 3 },
new { x = 3 }, new { x = 10}, new { x = 1 },
new { x = 5 }, new { x = 2 }, new { x = 1 },
new { x = 1 }, new { x = 9 }, new { x = 3 },
new { x = 11}, new { x = 10}, new { x = 1 },
new { x = 5 }, new { x = 2 }, new { x = 12 }};
var x = data.Aggregate(
new LinkedList<Holder>(),
(holdList,inItem) =>
{
if ((holdList.Last == null) || (holdList.Last.Value.count == 3))
{
holdList.AddLast(new Holder { max = inItem, count = 1});
}
else
{
if (holdList.Last.Value.max.x < inItem.x)
holdList.Last.Value.max = inItem;
holdList.Last.Value.count++;
}
return holdList;
},
(holdList) => { return holdList.Select((h) => h.max );} );
x.Dump("We expect 3,10,5,9,11,12");
}

Categories

Resources