Obtain the Sum of an IEnumerable collection in only one LINQ expression - c#

Let's suppose I have an inifite generator A(). What I want is to obtain the sum of all the numbers returned by A such that the sum does not exceed a value N in only one LINQ expression.
I'm wondering if there is an extension method that will help me with that?
The classic way would be:
int sum = 0;
foreach (int x in A()) {
sum += x;
if (sum > N) {
break;
}
}
return sum;
but I've been thinking about how to do it in only one expression without success...

Using standard idiomatic LINQ, this would be impossible. The semantics you would need is a combination of Aggregate() and TakeWhile(). Otherwise, you'd need to have side-effects which is a no-no in LINQ.
Here's an example of one way to do it with side-effects:
var temp = 0;
var sum = A().TakeWhile(i =>
{
var res = !(temp > N);
temp += i;
return res;
}).Sum();

If A is an infinite generator then there's no way of doing this in a single statement using only the built-in LINQ methods.
To do it cleanly, in a single statement, with no side-effects, you'd probably need to use some sort of Scan method to compute the prefix sum of the input sequence. Then you just need the first element greater than N. Easy!
int sum = A().Scan((s, x) => s + x).First(s => s > N);
// ...
public static class EnumerableExtensions
{
public static IEnumerable<T> Scan<T>(
this IEnumerable<T> source, Func<T, T, T> func)
{
if (source == null) throw new ArgumentNullException("source");
if (func == null) throw new ArgumentNullException("func");
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
T accumulator = e.Current;
yield return accumulator;
while (e.MoveNext())
{
accumulator = func(accumulator, e.Current);
yield return accumulator;
}
}
}
}
}

Sure there is a way to do this with a single LINQ-expression. The simplest I could come up with and still have some generality and elegance is:
public static int SumWhile(this IEnumerable<int> collection, Func<int, bool> condition)
{
int sum = 0;
foreach (int i in collection)
{
sum += i;
if (!condition(sum))
break;
}
return sum;
}
which can be called like:
int sum = A().SumWhile(i => i <= N);
Yeah, just a single LINQ-expression! Have fun with it

Probably the most near your initial idea :
int sum = 0;
int limit = 500;
A().TakeWhile(i => (sum += i) < limit).Count();
//Now the variable named sum contains the smaller sum of elements being >= limit
The Count() isn't used for its returning value but to force the actual enumerating.

Let's see if I have the requirements correct.
A() is an infinite generator. By definition, then, it generates values (in this case integers) forever.
You want to look for all of the values that are less than N, and add them together.
Linq isn't the issue. You won't be done adding until A() is finished generating... and that never happens.
BTW, the code you posted doesn't all up all of the values less than N... it adds up all the values until it finds one less than N, and then it quits looking. Is that what you meant?

I believe the horrific code below satisfies your requirements. :-)
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication12 {
public class Program {
public static void Main(string[] args) {
const int N=100;
int sum;
try {
sum=A().Aggregate((self, next) => {
if(self+next<=N)
return self+next;
else
throw new ResultException(self);
});
} catch(ResultException re) {
sum=re.Value;
}
Debug.Print("Sum="+sum);
}
private class ResultException : Exception {
public readonly int Value;
public ResultException(int value) {
Value=value;
}
}
private static IEnumerable<int> A() {
var i=0;
while(true) {
yield return i++;
}
}
}
}

int sum = A().Where(x => x < N).Sum();

Related

I am not understanding why my code for Linked List is not working?

I don't know what is wrong but the program is just not working. I will be really grateful if you help me.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
LinkedList<ulong> integers = new LinkedList<ulong>();
for(ulong i = 1; i <= 10; i++)
{
integers.AddLast(i);
}
Console.Write("Enter an integer: ");
ulong x = ulong.Parse(Console.ReadLine());
Console.WriteLine();
foreach(ulong integer in integers)
{
if(integer > x)
{
integers.Remove(integer);
}
}
integers.AddLast(x);
integers.AddLast(10);
foreach(ulong integer in integers)
{
Console.WriteLine(integer);
}
}
}
The condition of my task is: Create a LinkedList of 10 positive integers. The finished list is displayed on the screen. Enter a positive integer x on the keyboard, delete all items greater than x from the list, and add an item with a value of 10 after the last item in the x-value list. Display the changed list.
The first thing that calls my attention is that inside the foreach loop you are modifying the list that you are iterating over: integers
Try storing the list of items you want to remove in a separate list first. Then iterate through that list and delete all.
var toBeDeleted=new List<ulong>;
foreach(ulong integer in integers)
{
if(integer > x)
{
toBeDeleted.Add(integer);
}
}
foreach(ulong item in toBeDeleted)
{
integers.Remove(item);
}
You can also use the Remove(LinkedListNode) method. In that case in the code would be something like this(didn't test it so you might need to touch it to make it compile)
var toBeDeleted=new List<LinkedListNode<ulong>>;
foreach(LinkedListNode<ulong> integer in integers)
{
if(integer > x) //might need to cast it to ulong if it doesn't happen automatically.
{
toBeDeleted.Add(integer);
}
}
integers.Remove(toBeDeleted);
I ran your code. You are removing items in foreach loop. Try using "for" loop and iterating from the last element, to the first.
class Program
{
static void Main(string[] args)
{
LinkedList<ulong> integers = new LinkedList<ulong>();
for (ulong i = 1; i <= 10; i++)
{
integers.AddLast(i);
}
Console.Write("Enter an integer: ");
ulong x = ulong.Parse(Console.ReadLine());
Console.WriteLine();
for (int i = integers.Count-1; i >= 0; i--)
{
ulong a = integers.ElementAt(i);
if (a > x)
{
integers.Remove(a);
}
}
integers.AddLast(x);
integers.AddLast(10);
foreach (ulong integer in integers)
{
Console.WriteLine(integer);
}
Console.ReadKey();
}
}
C# List - Removing items while looping / iterating

SortedSet.Remove() does not remove anything

I am currently implementing Dijkstra's algorithm and I am using the C# SortedSet as a priority queue.
However, in order to keep track of what vertices I have already visited, I want to remove the first item from the priority queue.
Here is my code:
static int shortestPath(int start, int target)
{
SortedSet<int> PQ = new SortedSet<int>(new compareByVertEstimate());
for (int i = 0; i < n; i++)
{
if (i == start - 1)
vertices[i].estimate = 0;
else
vertices[i].estimate = int.MaxValue;
PQ.Add(i);
}
int noOfVisited = 0;
while (noOfVisited < n)
{
int u = PQ.First();
noOfVisited++;
foreach (Edge e in vertices[u].neighbours)
{
if (vertices[e.target.Item1].estimate > vertices[u].estimate + e.length)
{
vertices[e.target.Item1].estimate = vertices[u].estimate + e.length;
}
}
PQ.Remove(u);
}
return vertices[target - 1].estimate;
}
And this is the comparer:
public class compareByVertEstimate : IComparer<int>
{
public int Compare(int a, int b)
{
if (Program.vertices[a].estimate >= Program.vertices[b].estimate) return 1;
else return -1;
}
}
My priority queue does not explicitly hold vertices, instead I have an array of vertices and the priority queue holds the indices.
So the priority queue is sorted based on the 'estimate' integer that each vertex holds.
Now my problem is, I can easily retrieve the first element from the SortedSet using .First(), or .Min, but when I try to remove that element with .Remove(), the method returns false, and nothing gets removed. The SortedSet remains unchanged.
Any ideas on how to fix this?
Thanks in advance!
EDIT
I changed the Comparer to this:
public class compareByVertEstimate : IComparer<int>
{
public int Compare(int a, int b)
{
if (Program.vertices[a].estimate == Program.vertices[b].estimate) return 0;
else if (Program.vertices[a].estimate >= Program.vertices[b].estimate) return 1;
else return -1;
}
}
But now the priority queue doesn't contain all the right elements anymore.
(Note, the priority queue will contain pointers to vertices that have the same estimate value)
Your compare function never compares two elements as equal (return 0;).
Your collection will not be able to remove an element that is not equal to any element it holds.
Example:
public class compareByVertEstimate : IComparer<int>
{
public int Compare(int a, int b)
{
if (a == b) return 0;
if (Program.vertices[a].estimate >= Program.vertices[b].estimate) return 1;
return -1;
}
}
#hvd is correct of course, while the above version works, it's quite broken. A better comparer might be:
public class compareByVertEstimate : IComparer<int>
{
public int Compare(int a, int b)
{
var ae = Program.vertices[a].estimate;
var be = Program.vertices[b].estimate;
var result = ae.CompareTo(be);
if (result == 0) return a.CompareTo(b);
return result;
}
}

Separate functions without duplicating code

I am currently working on a program to traverse through a list of numbers with two different functions to find the sum and a specific value. Here is the code that I have implemented
class Program
{
static int i, sum;
static List<int> store = new List<int>();
static void Main(string[] args)
{
for (i = 0; i < 100; i++)
{
store.Add(i);
}
i = 0;
TraverseList();
Console.ReadLine();
}
static void TraverseList()
{
while (i < store.Count)
{
FindValue();
FindSum();
i++;
}
Console.WriteLine("The sum is {0}", sum);
}
static void FindValue()
{
if (store[i] == 40)
{
Console.WriteLine("Value is 40");
}
}
static void FindSum()
{
sum = sum + store[i];
}
}
I was thinking of separating FindSum and FindValue into two different functions and not calling them in TraverseList. Is there any other way of doing it rather the duplicating the common code of list traversal in those two functions as I have done here
class Program
{
static int i, sum;
static List<int> store = new List<int>();
static void Main(string[] args)
{
for (i = 0; i < 100; i++)
{
store.Add(i);
}
i = 0;
FindValue();
i = 0;
FindSum();
Console.ReadLine();
}
static void FindValue()
{
while (i < store.Count)
{
if (store[i] == 40)
{
Console.WriteLine("Value is 40");
}
i++;
}
}
static void FindSum()
{
while (i < store.Count)
{
sum = sum + store[i];
i++;
}
Console.WriteLine("The sum is {0}", sum);
}
}
To find the sum of a series of numbers you can use the simple LINQ function:
List<int> numbers = new List<int>();
int sum = numbers.Sum();
I am not sure what you mean by find a value. If you want to check if one of the numbers in a series is equal to a certain value you can use the LINQ function Any:
int myValue = 40;
bool hasMyValue = numbers.Any(i => i == myValue);
This uses a lambda expression which executes a function and passes each element in the collection to the function. The function returns true or false to indicate that the element is a match for the Any test.
If instead you want to check for how many numbers in a sequence match a certain value you can instead use the Count function like so:
int numberOfMatches = numbers.Count(i => i == myValue);
First thing - I would use foreach instead of while, regarding the duplicate code (assuming you are not using Linq) - I think it's fine
A taste how Linq can simplify your code:
var FindSum = store.Sum();
var FindValue = store.FindAll(x => x == 40);
I cannot stress enough how bad it is to have i and sum as class members. Especially i. It will make your code very fragile, and hard to work with. Try to make each method as isolated from the rest of the code as possible.
Try something like this instead:
static void Main( string[] args )
{
List<int> store = new List<int>();
for( int i = 0; i < 100; i++ )
store.Add( i );
FindValue( store );
FindSum( store );
Console.ReadLine();
}
static void FindValue( List<int> list )
{
for( int i = 0; i < list.Count; i++ )
{
if( list[i] == 40 )
Console.WriteLine( "Value is 40" );
}
}
static void FindSum( List<int> list )
{
int sum = 0;
for( int i = 0; i < list.Count; i++ )
sum += list[i];
Console.WriteLine( "The sum is {0}", sum );
}
It is perfectly fine (and normal) to duplicate the looping, it's just a single line. You could also use a foreach here.
Also, disregard everyone telling you to use LINQ. You're obviously new to programming and you should learn the basics first.

why a function which has yield return in it cannot be recursive?

i have a piece of code like this
class Program
{
static IEnumerable<string> GetSequences(string a)
{
yield return a;
GetSequences(a + ">");
}
static void Main(string[] args)
{
foreach (var n in GetSequences(">"))
Console.Write(n + ",");
}
}
i was expecting an output like this
,>>,>>>
but it doesn't. it printed only ">,". Does anyone knows what i am missing ?
Use the same foreach in function itself:
static IEnumerable<string> GetSequences(string a)
{
yield return a;
foreach (var n in GetSequences(a + ">"))
yield return n;
}
and don't forget to quit recursion.
The foreach loop only works with the yield return, and you don't have a yield return on your GetSequences() command in the GetSequences() method; whatever it returns doesn't get stored or returned. It is like you are doing this:
It's like you are doing this:
static IEnumerable<string> GetSequences(string a)
{
GetSequences(a + ">");
}
which of course doesn't have a return statement (it wouldn't compile, but you knew that).
After toying around with this for a little while, if you want to use recursion I would recommend you don't use an enumerable, particularly because loops and recursion are meant to serve separate purposes, and the foreach with IEnumerable works best with collections that have already been enumerated. The loop suggested above, as is, just enables endless recursion, and implementing an escape of the recursion like this:
static IEnumerable<string> GetSequences(string a)
{
if(a.Length > 100)
yield return a;
else
foreach (var n in GetSequences(a + ">"))
yield return n;
}
yields this output:
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>, (maybe to scale, I didn't want to count)
By implementing it like this I was able to get the output you wanted:
static string GetSequences(string a, int len)
{
if (a.Length < len)
{
return GetSequences(a + ">", len);
}
else
return a;
}
static void Main(string[] args)
{
for (int i = 1; i < 5; i++)
{
Console.Write(GetSequences(">", i) + ",");
}
Console.Read();
}
Of course, my integers are arbitrary, it will work with any length.
EDIT: I knew there was a way to do it the way abatishchev was saying, but I couldn't figure it out. After racking my brain, here is what I got:
static IEnumerable<string> GetSequences(string a)
{
if (a.Length < 100)
{
yield return a;
foreach (var n in GetSequences(a + ">"))
yield return n;
}else
yield break;
}
This has the output you want, although I still think using recursion with loops is a little funny.

Split a collection into `n` parts with LINQ? [duplicate]

This question already has answers here:
Split List into Sublists with LINQ
(34 answers)
Closed 1 year ago.
Is there a nice way to split a collection into n parts with LINQ?
Not necessarily evenly of course.
That is, I want to divide the collection into sub-collections, which each contains a subset of the elements, where the last collection can be ragged.
A pure linq and the simplest solution is as shown below.
static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
int i = 0;
var splits = from item in list
group item by i++ % parts into part
select part.AsEnumerable();
return splits;
}
}
EDIT: Okay, it looks like I misread the question. I read it as "pieces of length n" rather than "n pieces". Doh! Considering deleting answer...
(Original answer)
I don't believe there's a built-in way of partitioning, although I intend to write one in my set of additions to LINQ to Objects. Marc Gravell has an implementation here although I would probably modify it to return a read-only view:
public static IEnumerable<IEnumerable<T>> Partition<T>
(this IEnumerable<T> source, int size)
{
T[] array = null;
int count = 0;
foreach (T item in source)
{
if (array == null)
{
array = new T[size];
}
array[count] = item;
count++;
if (count == size)
{
yield return new ReadOnlyCollection<T>(array);
array = null;
count = 0;
}
}
if (array != null)
{
Array.Resize(ref array, count);
yield return new ReadOnlyCollection<T>(array);
}
}
static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
return list.Select((item, index) => new {index, item})
.GroupBy(x => x.index % parts)
.Select(x => x.Select(y => y.item));
}
}
Ok, I'll throw my hat in the ring. The advantages of my algorithm:
No expensive multiplication, division, or modulus operators
All operations are O(1) (see note below)
Works for IEnumerable<> source (no Count property needed)
Simple
The code:
public static IEnumerable<IEnumerable<T>>
Section<T>(this IEnumerable<T> source, int length)
{
if (length <= 0)
throw new ArgumentOutOfRangeException("length");
var section = new List<T>(length);
foreach (var item in source)
{
section.Add(item);
if (section.Count == length)
{
yield return section.AsReadOnly();
section = new List<T>(length);
}
}
if (section.Count > 0)
yield return section.AsReadOnly();
}
As pointed out in the comments below, this approach doesn't actually address the original question which asked for a fixed number of sections of approximately equal length. That said, you can still use my approach to solve the original question by calling it this way:
myEnum.Section(myEnum.Count() / number_of_sections + 1)
When used in this manner, the approach is no longer O(1) as the Count() operation is O(N).
This is same as the accepted answer, but a much simpler representation:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> items,
int numOfParts)
{
int i = 0;
return items.GroupBy(x => i++ % numOfParts);
}
The above method splits an IEnumerable<T> into N number of chunks of equal sizes or close to equal sizes.
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> items,
int partitionSize)
{
int i = 0;
return items.GroupBy(x => i++ / partitionSize).ToArray();
}
The above method splits an IEnumerable<T> into chunks of desired fixed size with total number of chunks being unimportant - which is not what the question is about.
The problem with the Split method, besides being slower, is that it scrambles the output in the sense that the grouping will be done on the basis of i'th multiple of N for each position, or in other words you don't get the chunks in the original order.
Almost every answer here either doesn't preserve order, or is about partitioning and not splitting, or is plainly wrong. Try this which is faster, preserves order but a lil' more verbose:
public static IEnumerable<IEnumerable<T>> Split<T>(this ICollection<T> items,
int numberOfChunks)
{
if (numberOfChunks <= 0 || numberOfChunks > items.Count)
throw new ArgumentOutOfRangeException("numberOfChunks");
int sizePerPacket = items.Count / numberOfChunks;
int extra = items.Count % numberOfChunks;
for (int i = 0; i < numberOfChunks - extra; i++)
yield return items.Skip(i * sizePerPacket).Take(sizePerPacket);
int alreadyReturnedCount = (numberOfChunks - extra) * sizePerPacket;
int toReturnCount = extra == 0 ? 0 : (items.Count - numberOfChunks) / extra + 1;
for (int i = 0; i < extra; i++)
yield return items.Skip(alreadyReturnedCount + i * toReturnCount).Take(toReturnCount);
}
The equivalent method for a Partition operation here
I have been using the Partition function I posted earlier quite often. The only bad thing about it was that is wasn't completely streaming. This is not a problem if you work with few elements in your sequence. I needed a new solution when i started working with 100.000+ elements in my sequence.
The following solution is a lot more complex (and more code!), but it is very efficient.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
namespace LuvDaSun.Linq
{
public static class EnumerableExtensions
{
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> enumerable, int partitionSize)
{
/*
return enumerable
.Select((item, index) => new { Item = item, Index = index, })
.GroupBy(item => item.Index / partitionSize)
.Select(group => group.Select(item => item.Item) )
;
*/
return new PartitioningEnumerable<T>(enumerable, partitionSize);
}
}
class PartitioningEnumerable<T> : IEnumerable<IEnumerable<T>>
{
IEnumerable<T> _enumerable;
int _partitionSize;
public PartitioningEnumerable(IEnumerable<T> enumerable, int partitionSize)
{
_enumerable = enumerable;
_partitionSize = partitionSize;
}
public IEnumerator<IEnumerable<T>> GetEnumerator()
{
return new PartitioningEnumerator<T>(_enumerable.GetEnumerator(), _partitionSize);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class PartitioningEnumerator<T> : IEnumerator<IEnumerable<T>>
{
IEnumerator<T> _enumerator;
int _partitionSize;
public PartitioningEnumerator(IEnumerator<T> enumerator, int partitionSize)
{
_enumerator = enumerator;
_partitionSize = partitionSize;
}
public void Dispose()
{
_enumerator.Dispose();
}
IEnumerable<T> _current;
public IEnumerable<T> Current
{
get { return _current; }
}
object IEnumerator.Current
{
get { return _current; }
}
public void Reset()
{
_current = null;
_enumerator.Reset();
}
public bool MoveNext()
{
bool result;
if (_enumerator.MoveNext())
{
_current = new PartitionEnumerable<T>(_enumerator, _partitionSize);
result = true;
}
else
{
_current = null;
result = false;
}
return result;
}
}
class PartitionEnumerable<T> : IEnumerable<T>
{
IEnumerator<T> _enumerator;
int _partitionSize;
public PartitionEnumerable(IEnumerator<T> enumerator, int partitionSize)
{
_enumerator = enumerator;
_partitionSize = partitionSize;
}
public IEnumerator<T> GetEnumerator()
{
return new PartitionEnumerator<T>(_enumerator, _partitionSize);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
class PartitionEnumerator<T> : IEnumerator<T>
{
IEnumerator<T> _enumerator;
int _partitionSize;
int _count;
public PartitionEnumerator(IEnumerator<T> enumerator, int partitionSize)
{
_enumerator = enumerator;
_partitionSize = partitionSize;
}
public void Dispose()
{
}
public T Current
{
get { return _enumerator.Current; }
}
object IEnumerator.Current
{
get { return _enumerator.Current; }
}
public void Reset()
{
if (_count > 0) throw new InvalidOperationException();
}
public bool MoveNext()
{
bool result;
if (_count < _partitionSize)
{
if (_count > 0)
{
result = _enumerator.MoveNext();
}
else
{
result = true;
}
_count++;
}
else
{
result = false;
}
return result;
}
}
}
Enjoy!
Interesting thread. To get a streaming version of Split/Partition, one can use enumerators and yield sequences from the enumerator using extension methods. Converting imperative code to functional code using yield is a very powerful technique indeed.
First an enumerator extension that turns a count of elements into a lazy sequence:
public static IEnumerable<T> TakeFromCurrent<T>(this IEnumerator<T> enumerator, int count)
{
while (count > 0)
{
yield return enumerator.Current;
if (--count > 0 && !enumerator.MoveNext()) yield break;
}
}
And then an enumerable extension that partitions a sequence:
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> seq, int partitionSize)
{
var enumerator = seq.GetEnumerator();
while (enumerator.MoveNext())
{
yield return enumerator.TakeFromCurrent(partitionSize);
}
}
The end result is a highly efficient, streaming and lazy implementation that relies on very simple code.
Enjoy!
I use this:
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> instance, int partitionSize)
{
return instance
.Select((value, index) => new { Index = index, Value = value })
.GroupBy(i => i.Index / partitionSize)
.Select(i => i.Select(i2 => i2.Value));
}
As of .NET 6 you can use Enumerable.Chunk<TSource>(IEnumerable<TSource>, Int32).
This is memory efficient and defers execution as much as possible (per batch) and operates in linear time O(n)
public static IEnumerable<IEnumerable<T>> InBatchesOf<T>(this IEnumerable<T> items, int batchSize)
{
List<T> batch = new List<T>(batchSize);
foreach (var item in items)
{
batch.Add(item);
if (batch.Count >= batchSize)
{
yield return batch;
batch = new List<T>();
}
}
if (batch.Count != 0)
{
//can't be batch size or would've yielded above
batch.TrimExcess();
yield return batch;
}
}
There are lots of great answers for this question (and its cousins). I needed this myself and had created a solution that is designed to be efficient and error tolerant in a scenario where the source collection can be treated as a list. It does not use any lazy iteration so it may not be suitable for collections of unknown size that may apply memory pressure.
static public IList<T[]> GetChunks<T>(this IEnumerable<T> source, int batchsize)
{
IList<T[]> result = null;
if (source != null && batchsize > 0)
{
var list = source as List<T> ?? source.ToList();
if (list.Count > 0)
{
result = new List<T[]>();
for (var index = 0; index < list.Count; index += batchsize)
{
var rangesize = Math.Min(batchsize, list.Count - index);
result.Add(list.GetRange(index, rangesize).ToArray());
}
}
}
return result ?? Enumerable.Empty<T[]>().ToList();
}
static public void TestGetChunks()
{
var ids = Enumerable.Range(1, 163).Select(i => i.ToString());
foreach (var chunk in ids.GetChunks(20))
{
Console.WriteLine("[{0}]", String.Join(",", chunk));
}
}
I have seen a few answers across this family of questions that use GetRange and Math.Min. But I believe that overall this is a more complete solution in terms of error checking and efficiency.
protected List<List<int>> MySplit(int MaxNumber, int Divider)
{
List<List<int>> lst = new List<List<int>>();
int ListCount = 0;
int d = MaxNumber / Divider;
lst.Add(new List<int>());
for (int i = 1; i <= MaxNumber; i++)
{
lst[ListCount].Add(i);
if (i != 0 && i % d == 0)
{
ListCount++;
d += MaxNumber / Divider;
lst.Add(new List<int>());
}
}
return lst;
}
Great Answers, for my scenario i tested the accepted answer , and it seems it does not keep order. there is also great answer by Nawfal that keeps order.
But in my scenario i wanted to split the remainder in a normalized way,
all answers i saw spread the remainder or at the beginning or at the end.
My answer also takes the remainder spreading in more normalized way.
static class Program
{
static void Main(string[] args)
{
var input = new List<String>();
for (int k = 0; k < 18; ++k)
{
input.Add(k.ToString());
}
var result = splitListIntoSmallerLists(input, 15);
int i = 0;
foreach(var resul in result){
Console.WriteLine("------Segment:" + i.ToString() + "--------");
foreach(var res in resul){
Console.WriteLine(res);
}
i++;
}
Console.ReadLine();
}
private static List<List<T>> splitListIntoSmallerLists<T>(List<T> i_bigList,int i_numberOfSmallerLists)
{
if (i_numberOfSmallerLists <= 0)
throw new ArgumentOutOfRangeException("Illegal value of numberOfSmallLists");
int normalizedSpreadRemainderCounter = 0;
int normalizedSpreadNumber = 0;
//e.g 7 /5 > 0 ==> output size is 5 , 2 /5 < 0 ==> output is 2
int minimumNumberOfPartsInEachSmallerList = i_bigList.Count / i_numberOfSmallerLists;
int remainder = i_bigList.Count % i_numberOfSmallerLists;
int outputSize = minimumNumberOfPartsInEachSmallerList > 0 ? i_numberOfSmallerLists : remainder;
//In case remainder > 0 we want to spread the remainder equally between the others
if (remainder > 0)
{
if (minimumNumberOfPartsInEachSmallerList > 0)
{
normalizedSpreadNumber = (int)Math.Floor((double)i_numberOfSmallerLists / remainder);
}
else
{
normalizedSpreadNumber = 1;
}
}
List<List<T>> retVal = new List<List<T>>(outputSize);
int inputIndex = 0;
for (int i = 0; i < outputSize; ++i)
{
retVal.Add(new List<T>());
if (minimumNumberOfPartsInEachSmallerList > 0)
{
retVal[i].AddRange(i_bigList.GetRange(inputIndex, minimumNumberOfPartsInEachSmallerList));
inputIndex += minimumNumberOfPartsInEachSmallerList;
}
//If we have remainder take one from it, if our counter is equal to normalizedSpreadNumber.
if (remainder > 0)
{
if (normalizedSpreadRemainderCounter == normalizedSpreadNumber-1)
{
retVal[i].Add(i_bigList[inputIndex]);
remainder--;
inputIndex++;
normalizedSpreadRemainderCounter=0;
}
else
{
normalizedSpreadRemainderCounter++;
}
}
}
return retVal;
}
}
If order in these parts is not very important you can try this:
int[] array = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int n = 3;
var result =
array.Select((value, index) => new { Value = value, Index = index }).GroupBy(i => i.Index % n, i => i.Value);
// or
var result2 =
from i in array.Select((value, index) => new { Value = value, Index = index })
group i.Value by i.Index % n into g
select g;
However these can't be cast to IEnumerable<IEnumerable<int>> by some reason...
This is my code, nice and short.
<Extension()> Public Function Chunk(Of T)(ByVal this As IList(Of T), ByVal size As Integer) As List(Of List(Of T))
Dim result As New List(Of List(Of T))
For i = 0 To CInt(Math.Ceiling(this.Count / size)) - 1
result.Add(New List(Of T)(this.GetRange(i * size, Math.Min(size, this.Count - (i * size)))))
Next
Return result
End Function
This is my way, listing items and breaking row by columns
int repat_count=4;
arrItems.ForEach((x, i) => {
if (i % repat_count == 0)
row = tbo.NewElement(el_tr, cls_min_height);
var td = row.NewElement(el_td);
td.innerHTML = x.Name;
});
I was looking for a split like the one with string, so the whole List is splitted according to some rule, not only the first part, this is my solution
List<int> sequence = new List<int>();
for (int i = 0; i < 2000; i++)
{
sequence.Add(i);
}
int splitIndex = 900;
List<List<int>> splitted = new List<List<int>>();
while (sequence.Count != 0)
{
splitted.Add(sequence.Take(splitIndex).ToList() );
sequence.RemoveRange(0, Math.Min(splitIndex, sequence.Count));
}
Here is a little tweak for the number of items instead of the number of parts:
public static class MiscExctensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int nbItems)
{
return (
list
.Select((o, n) => new { o, n })
.GroupBy(g => (int)(g.n / nbItems))
.Select(g => g.Select(x => x.o))
);
}
}
below code returns both given number of chunks also with sorted data
static IEnumerable<IEnumerable<T>> SplitSequentially<T>(int chunkParts, List<T> inputList)
{
List<int> Splits = split(inputList.Count, chunkParts);
var skipNumber = 0;
List<List<T>> list = new List<List<T>>();
foreach (var count in Splits)
{
var internalList = inputList.Skip(skipNumber).Take(count).ToList();
list.Add(internalList);
skipNumber += count;
}
return list;
}
static List<int> split(int x, int n)
{
List<int> list = new List<int>();
if (x % n == 0)
{
for (int i = 0; i < n; i++)
list.Add(x / n);
}
else
{
// upto n-(x % n) the values
// will be x / n
// after that the values
// will be x / n + 1
int zp = n - (x % n);
int pp = x / n;
for (int i = 0; i < n; i++)
{
if (i >= zp)
list.Add((pp + 1));
else
list.Add(pp);
}
}
return list;
}
int[] items = new int[] { 0,1,2,3,4,5,6,7,8,9, 10 };
int itemIndex = 0;
int groupSize = 2;
int nextGroup = groupSize;
var seqItems = from aItem in items
group aItem by
(itemIndex++ < nextGroup)
?
nextGroup / groupSize
:
(nextGroup += groupSize) / groupSize
into itemGroup
select itemGroup.AsEnumerable();
Just came across this thread, and most of the solutions here involve adding items to collections, effectively materialising each page before returning it. This is bad for two reasons - firstly if your pages are large there's a memory overhead to filling the page, secondly there are iterators which invalidate previous records when you advance to the next one (for example if you wrap a DataReader within an enumerator method).
This solution uses two nested enumerator methods to avoid any need to cache items into temporary collections. Since the outer and inner iterators are traversing the same enumerable, they necessarily share the same enumerator, so it's important not to advance the outer one until you're done with processing the current page. That said, if you decide not to iterate all the way through the current page, when you move to the next page this solution will iterate forward to the page boundary automatically.
using System.Collections.Generic;
public static class EnumerableExtensions
{
/// <summary>
/// Partitions an enumerable into individual pages of a specified size, still scanning the source enumerable just once
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="enumerable">The source enumerable</param>
/// <param name="pageSize">The number of elements to return in each page</param>
/// <returns></returns>
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> enumerable, int pageSize)
{
var enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext())
{
var indexWithinPage = new IntByRef { Value = 0 };
yield return SubPartition(enumerator, pageSize, indexWithinPage);
// Continue iterating through any remaining items in the page, to align with the start of the next page
for (; indexWithinPage.Value < pageSize; indexWithinPage.Value++)
{
if (!enumerator.MoveNext())
{
yield break;
}
}
}
}
private static IEnumerable<T> SubPartition<T>(IEnumerator<T> enumerator, int pageSize, IntByRef index)
{
for (; index.Value < pageSize; index.Value++)
{
yield return enumerator.Current;
if (!enumerator.MoveNext())
{
yield break;
}
}
}
private class IntByRef
{
public int Value { get; set; }
}
}

Categories