I have a list and I need to output each subset of the list
for example a b c d e
would output to
a
b
c
d
e
ab
ac
ad
ae
abc
abd
abe
bcd
bce
....
abcde
I believe the correct term is combination no element should be duplicated on the same line
I was going to attempt this with a series of loops but im not even sure wehre to start
any suggestions?
This will generate the set you want, but in a different order (I sort by alphabet at the end, you'd want to sort by length as well).
You'll end up with:
a
ab
abc
abcd
abcde
abce
...
d
de
e
So, every possible subset (aside from the empty string), while maintaining the order of the original list.
The idea is to add each element to to a growing list. With every new element, add it first, and then add it to all existing elements.
So, start with 'a'.
Go on to 'b'. Add it to the list. We now have {'a', 'b'}.
Add it to existing elements, so we have 'ab'. Now we have {'a', 'b', 'ab'}.
Then 'c', and add it to existing elements to get 'ac', 'bc', 'abc': {'a', 'b', 'ab', 'c', 'ac', 'bc', abc'}. So forth until we're done.
string set = "abcde";
// Init list
List<string> subsets = new List<string>();
// Loop over individual elements
for (int i = 1; i < set.Length; i++)
{
subsets.Add(set[i - 1].ToString());
List<string> newSubsets = new List<string>();
// Loop over existing subsets
for (int j = 0; j < subsets.Count; j++)
{
string newSubset = subsets[j] + set[i];
newSubsets.Add(newSubset);
}
subsets.AddRange(newSubsets);
}
// Add in the last element
subsets.Add(set[set.Length - 1].ToString());
subsets.Sort();
Console.WriteLine(string.Join(Environment.NewLine, subsets));
if all you need are combinations of the elements in your original list, you can transform the problem into the following: you have a bit array of size N, and you want to find all possible choices for the elements of the array. For example, if your original list is
a b c d e
then your array can be
0 1 0 0 0
which results in an output of
b
or the array can be
1 0 1 1 0
which returns
acd
this is a simple recursion problem that can be solved in an O(2^n) time
edit adding pseudo-code for recursion algorithm:
CreateResultSet(List<int> currentResult, int step)
{
if (the step number is greater than the length of the original list)
{
add currentResult to list of all results
return
}
else
{
add 0 at the end of currentResult
call CreateResultSet(currentResult, step+1)
add 1 at the end of currentResult
call CreateResultSet(currentResult, step+1)
}
}
for every item in the list of all results
display the result associated to it (i.e. from 1 0 1 1 0 display acd)
This will work with any collection. I modified #Sapp's answer a little
static List<List<T>> GetSubsets<T>(IEnumerable<T> Set)
{
var set = Set.ToList<T>();
// Init list
List<List<T>> subsets = new List<List<T>>();
subsets.Add(new List<T>()); // add the empty set
// Loop over individual elements
for (int i = 1; i < set.Count; i++)
{
subsets.Add(new List<T>(){set[i - 1]});
List<List<T>> newSubsets = new List<List<T>>();
// Loop over existing subsets
for (int j = 0; j < subsets.Count; j++)
{
var newSubset = new List<T>();
foreach(var temp in subsets[j])
newSubset.Add(temp);
newSubset.Add(set[i]);
newSubsets.Add(newSubset);
}
subsets.AddRange(newSubsets);
}
// Add in the last element
subsets.Add(new List<T>(){set[set.Count - 1]});
//subsets.Sort();
return subsets;
}
**And then if I have a set of strings I will use it as:
Here is some code I made. It constructs a list of all possible strings from an alphabet, of lengths 1 to maxLength: (in other words, we are calculating the powers of the alphabet)
static class StringBuilder<T>
{
public static List<List<T>> CreateStrings(List<T> alphabet, int maxLength)
{
// This will hold all the strings which we create
List<List<T>> strings = new List<List<T>>();
// This will hold the string which we created the previous time through
// the loop (they will all have length i in the loop)
List<List<T>> lastStrings = new List<List<T>>();
foreach (T t in alphabet)
{
// Populate it with the string of length 1 read directly from alphabet
lastStrings.Add(new List<T>(new T[] { t }));
}
// This holds the string we make by appending each element from the
// alphabet to the strings in lastStrings
List<List<T>> newStrings;
// Here we make string2 for each length 2 to maxLength
for (int i = 0; i < maxLength; ++i)
{
newStrings = new List<List<T>>();
foreach (List<T> s in lastStrings)
{
newStrings.AddRange(AppendElements(s, alphabet));
}
strings.AddRange(lastStrings);
lastStrings = newStrings;
}
return strings;
}
public static List<List<T>> AppendElements(List<T> list, List<T> alphabet)
{
// Here we just append an each element in the alphabet to the given list,
// creating a list of new string which are one element longer.
List<List<T>> newList = new List<List<T>>();
List<T> temp = new List<T>(list);
foreach (T t in alphabet)
{
// Append the element
temp.Add(t);
// Add our new string to the collection
newList.Add(new List<T>(temp));
// Remove the element so we can make another string using
// the next element of the alphabet
temp.RemoveAt(temp.Count-1);
}
return newList;
}
}
something on the lines of an extended while loop :
<?
$testarray[0] = "a";
$testarray[1] = "b";
$testarray[2] = "c";
$testarray[3] = "d";
$testarray[4] = "e";
$x=0;
$y = 0;
while($x<=4) {
$subsetOne[$x] .= $testarray[$y];
$subsetOne[$x] .= $testarray[$x];
$subsetTwo[$x] .= $testarray[$y];
$subsetTwo[$x] .= $subsetOne[$x];
$subsetThree[$x] = str_replace("aa","ab",$subsetTwo[$x]);
$x++;
}
?>
Related
string[] n = Console.ReadLine().Split();
for (int i = 1; i <6; i++)
{
int[] a = long.Parse(n[i]);
}
If each number in a row separated with whitespace - you can use your Split more efficiently:
int[] array = Console.ReadLine().Split().Select(int.Parse).ToArray(); // Improved according to #Caius Jard comment
If need array of longs - replace int.Parse with long.Parse and declare variable as long[] array.
You need to add using System.Linq to get access to ToArray extension method.
EDIT.
Insprired by #Caius Jard, non-LINQ version:
// Read input line and split it by whitespace (default)
string[] values = Console.ReadLine().Split();
// Declare arrays for Int or Long values.
// Arrays sizes equals to size of array of input values
int[] arrayOfInts = new int[values.Length];
long[] arrayOfLongs = new long[values.Length];
// Iterate with for loop over amount of input values.
for (int i = 0; i < values.Length; i++)
{
// Convert trimmed input value to Int32
arrayOfInts[i] = int.Parse(values[i].Trim());
// Or to Int64
arrayOfLongs[i] = long.Parse(values[i].Trim());
}
int.Parse and long.Parse may be replaced with Convert.ToInt32 and Convert.ToInt64 if needed.
Please, don't use magic constants: i < 6. Here 6 doesn't necessary equal to n.Length.
You can put it as
string[] n = Console.ReadLine().Split();
List<int> list = new List<int>();
for (int i = 0; i < n.Length; ++i) {
if (int.TryParse(n[i], out int value))
list.Add(value);
else {
// Invalid item within user input, say "bla-bla-bla"
//TODO: either reject the input or ignore the item (here we ignore)
}
}
if (list.Count == a.Length) {
// We have exactly a.Length - 6 valid integer items
for (int i = 0; i < a.Length; ++i)
a[i] = list[i];
}
else {
//TODO: erroneous input: we have too few or too many items
}
Hi I'm a little bit stuck in C#. I'm new on it.
This is my problem:
I have a list made up of 63 double numbers (let's call it "big list").
I want to split this list in 6 list with the following rule:
The first list consists of the first 8 elements of the big list;
The second list goes from the 9th element of the big list to the (9+8=17th) element of the big list;
The third list goes from the 18th element of the big list to the (18+8+1=27th) element of the big list;
The fourth list goes from the 28th element of the big list to the (28+8+2=38th) element of the big list;
The fifth list goes from the 39th element of the big list to the (39+8+3=50th) element of the big list;
The sixth list goes from the 51th element of the big list to the (51+8+4=63th) element of the big list;
How can I do it? thanks a lot in advance for your help!
i've tried in this way but it gives me error "cannot apply indexing with [] to an expression of type method group"
List listsplitted = new List();
for (int i = 0; i < 6; i++)
{
for (int j = 8; j < 8 + i + 1; j++)
{
Listsplitted[i] = biglist.Take[j];
}
}
It is a very simple approach with the IEnumerable extensions Skip and Take
List<double> first = bigList.Take(8).ToList();
List<double> second = bigList.Skip(8).Take(8).ToList();
List<double> third = bigList.Skip(16).Take(9).ToList();
List<double> fourth = bigList.Skip(25).Take(10).ToList();
List<double> fifth = bigList.Skip(35).Take(11).ToList();
// The last one is without Take to get every remaining element
List<double> sixth = bigList.Skip(46).ToList();
Of course you should check if the indexes are correct for your requirements. These indexes doesn't skip any elements from your bigList
You can make this approach more generic with something like this
void Main()
{
var bigList = GetYourBigList();
List<Tuple<int, int>> positions = new List<Tuple<int, int>>
{
new Tuple<int, int>(0,8),
new Tuple<int, int>(8,8),
new Tuple<int, int>(16,9),
new Tuple<int, int>(25,10),
new Tuple<int, int>(35,11),
new Tuple<int, int>(46,13)
};
List<List<int>> result = SplitTheList(bigList, positions);
foreach (var list in result)
{
foreach (var temp in list)
Console.WriteLine(temp);
Console.WriteLine("--------------------");
}
}
List<List<int>> SplitTheList(List<int> r, List<Tuple<int, int>> positions)
{
List<List<int>> result = new List<List<int>>();
foreach(var x in positions)
result.Add(r.Skip(x.Item1).Take(x.Item2).ToList());
return result;
}
You can do it using GetRange function:
List<double> part1= big_list.GetRange(0, 8);//Retrieves 8 items starting with index '0'
List<double> part2= big_list.GetRange(8, 9);//Retrieves 9 items starting with index '8'
Or if you don't want to give different names to all parts, you can create a list of lists:
List<List<double>> listoflists = new List<List<double>>();
listoflists.Add(big_list.GetRange(0, 8));//Retrieves 8 items starting with index '0'
listoflists.Add(big_list.GetRange(8, 9));//Retrieves 9 items starting with index '8'
for(int i=0; i<listoflists.Count;i++){
for(int j=0; j<listoflists[i].Count; j++){
Console.Write(listoflists[i][j] + " ");
}
Console.WriteLine();
}
if you are insisting on do the operation in one single for statement you can use the following code
const int arrSize = 6;
var splitedLists = new List<List<int>>(arrSize);
var defaultTake = 8;
var defaultSkip = 0;
for (var i = 1; i <= arrSize; i++)
{
if (i >= 3)
defaultSkip--;
splitedLists.Add(array.Skip(defaultSkip).Take(defaultTake + 1).ToList());
if (i >= 2)
defaultTake++;
defaultSkip = defaultSkip + defaultTake + 1;
}
If you can replace the list with an array, you can do without copying the data. You can use ArraySegment (or Span/Memory in newer versions of the language) to do this.
var array = Enumerable.Range(0, 63).Select(i => (double)i).ToArray();
var splitted = new List<ArraySegment<double>>();
int offset = 0;
int count = 8;
for (int i = 0; i < 6; i++)
{
splitted.Add(new ArraySegment<double>(array, offset, count));
offset += count;
count++;
}
// see what we have
foreach (var seg in splitted)
Console.WriteLine(seg.Offset + " " + seg.Count);
// work with segments
var segment = splitted[3];
segment[5] = 555555;
// the main array has also changed
Console.WriteLine(string.Join(" ", array));
Note that the segments do not store copies of the data, but refer to the data in the main array.
User can pass any number of list with same number of elements in it. Example- user has passed below 3 (could be dynamic with same number of elements in it) list -
hospitalId - H11, H12, H13...n
patientId - P11, P12, P13...n
statusId - S11, S13, S11...n
What is the efficient way of creating a set out of it and storing it as a string in below format? Need a c# code for it.
expected output -
"((H11,P11, S11), (H12, P12, S13), (H13, P13, S11))"
You should iterate through your list and append them index wise to prepare the result.
StringBuilder builder = new StringBuilder();
builder.Append("(");
for(var index = 0; index < n; index++)
{
builder.AppendFormat("({0}, {1}, {2})", hospitalId[index], patientId[index], statusId[index]);
}
builder.Append(")");
var result = builder.ToString();
If you have n number of List<T> items with the same length, a basic loop will do the trick. Here's a version as an extension method that will take any number of lists as an input:
public static IEnumerable<IEnumerable<T>> ZipMultiple<T>(this List<List<T>> source)
{
var counts = source.Select(s => s.Count).Distinct();
if (counts.Count() != 1)
{
throw new ArgumentException("Lists aren't the same length");
}
for (var i = 0; i < counts.First(); i++)
{
var item = new List<T>();
for (var j = 0; j < source.Count; j++)
{
item.Add(source[j][i]);
}
yield return item;
}
}
After that, it's pretty simple to convert the result into a string in another loop, or you can do it as a single liner:
var zipped = lists.ZipMultiple();
var output = $"({string.Join(", ", zipped.Select(x => $"({string.Join(",", x)})"))})";
I am trying to create a program that is a base for creating possible combinations of a sequence, string or a number. This is some sort of encryption / decryption program. I am using Visual Studio 2013 and C#. What I am trying to do is to generate a power set out of a sequence, but I am little bit confused and can't proceed any further. Here is the code.
public static void randomSeq()
{
int temp = 0;
string seq = "1234";
var sb = new StringBuilder();
char[] bits = seq.Select((char c) => c).ToArray();
Console.Write("Given Sequence: ");
Console.Write(seq);
Console.WriteLine();
Console.WriteLine("Generated possiblities");
foreach (char item in bits)
Console.WriteLine(item);
do
{
if (temp <= 2)
{
for (int i = temp + 1; i < bits.Length; i++)
{
sb.Append(bits[temp]);
sb.Append(bits[i]);
Console.WriteLine(sb);
sb.Clear();
}
}
else if (temp > 2)
{
for (int k = 0; k < temp; k++)
sb.Append(bits[k]);
for (int l = temp + 1; l < bits.Length; l++)
{
sb.Append(bits[temp]);
sb.Append(bits[l]);
Console.WriteLine(sb);
sb.Clear();
}
}
temp++;
}
while (temp != bits.Length);
}
I want this code to be generic i.e. I pass any sequence and it generates a power set for me. Then I want to reuse it further in my program. I can do the rest simply I am stuck in generating the power set. Can someone help me?.
Power set is easy to generate if one is familiar with bits. For the set of N elements, there will be 2^N subsets which will go to power set (including empty set and initial set). So each element will be either IN or OUT (1 or 0 in other words).
Taking this into consideration, it is easy to represent subsets of the set as bit masks. Then enumerating through all possible bit masks, it is possible construct the whole power sets. In order to do this we need to examine each bit in bit mask and take element of input set if there is 1 in that place. Below is example for string (collection of chars) as input. It can be easily rewritten to work for collection of any type values.
private static List<string> PowerSet(string input)
{
int n = input.Length;
// Power set contains 2^N subsets.
int powerSetCount = 1 << n;
var ans = new List<string>();
for (int setMask = 0; setMask < powerSetCount; setMask++)
{
var s = new StringBuilder();
for (int i = 0; i < n; i++)
{
// Checking whether i'th element of input collection should go to the current subset.
if ((setMask & (1 << i)) > 0)
{
s.Append(input[i]);
}
}
ans.Add(s.ToString());
}
return ans;
}
Example
Suppose you have string "xyz" as input, it contains 3 elements, than there will be 2^3 == 8 elements in power set. If you will be iterating from 0 to 7 you will get the following table. Columns: (10-base integer; bits representation (2-base); subset of initial set).
0 000 ...
1 001 ..z
2 010 .y.
3 011 .yz
4 100 x..
5 101 x.z
6 110 xy.
7 111 xyz
You can notice that third column contains all subsets of initial string "xyz"
Another approach (twice faster) and generic implementation
Inspired by Eric's idea, I have implemented another variant of this algorithm (without bits now). Also I made it generic. I believe this code is near to fastest of what can be written for Power Set calculation. Its complexity is the same as for bits approach O(n * 2^n), but for this approach constant is halved.
public static T[][] FastPowerSet<T>(T[] seq)
{
var powerSet = new T[1 << seq.Length][];
powerSet[0] = new T[0]; // starting only with empty set
for (int i = 0; i < seq.Length; i++)
{
var cur = seq[i];
int count = 1 << i; // doubling list each time
for (int j = 0; j < count; j++)
{
var source = powerSet[j];
var destination = powerSet[count + j] = new T[source.Length + 1];
for (int q = 0; q < source.Length; q++)
destination[q] = source[q];
destination[source.Length] = cur;
}
}
return powerSet;
}
SergeyS's approach is perfectly reasonable. Here's an alternative way to think about it.
For the purposes of this answer I'm going to assume that "sets" are finite sequences.
We define the function P recursively as follows.
A set is either empty, or a single item H followed by a set T.
P(empty) --> { empty }
P(H : T) --> the union of P(T) and every element of P(T) prepended with H.
Let's try that out. What's the power set of {Apple, Banana, Cherry}?
It's not an empty set, so the power set of {Apple, Banana, Cherry} is the power set of {Banana, Cherry}, plus the sets formed by prepending Apple to each.
So we need to know the power set of {Banana, Cherry}. It's the power set of {Cherry} plus the sets form by prepending Banana to each.
So we need to know the power set of {Cherry}. It's the power set of the empty set, plus the sets formed by prepending Cherry to each.
So we need to know the power set of the empty set. It's the set containing the empty set. { {} }
Now prepend each element with Cherry and take the union. That's { {Cherry}, {} }. That gives us the power set of { Cherry }. Remember we needed that to find the power set of {Banana, Cherry}, so we union it with Banana prepended to each and get { {Banana, Cherry}, {Banana}, {Cherry}, {}} and that's the power set of {Banana, Cherry}.
Now we needed that to get the power set of {Apple, Banana, Cherry}, so union it with Apple appended to each and we have { {Apple, Banana, Cherry}, {Apple, Banana}, {Apple, Cherry}, {Apple}, {Banana, Cherry}, {Banana}, {Cherry}, {}} and we're done.
The code should be straightforward to write. First we'll need a helper method:
static IEnumerable<T> Prepend<T>(this IEnumerable<T> tail, T head)
{
yield return head;
foreach(T item in tail) yield return item;
}
And now the code is a straightforward translation of the description of the algorithm:
static IEnumerable<IEnumerable<T>> PowerSet<T>(this IEnumerable<T> items)
{
if (!items.Any())
yield return items; // { { } }
else
{
var head = items.First();
var powerset = items.Skip(1).PowerSet().ToList();
foreach(var set in powerset) yield return set.Prepend(head);
foreach(var set in powerset) yield return set;
}
}
Make sense?
----------- UPDATE ----------------
Sergey points out correctly that my code has a Schlemiel the Painter algorithm and therefore consumes huge amounts of time and memory; good catch Sergey. Here's an efficient version that uses an immutable stack:
class ImmutableList<T>
{
public static readonly ImmutableList<T> Empty = new ImmutableList<T>(null, default(T));
private ImmutableList(ImmutableList<T> tail, T head)
{
this.Head = head;
this.Tail = tail;
}
public T Head { get; private set; }
public ImmutableList<T> Tail { get; private set; }
public ImmutableList<T> Push(T head)
{
return new ImmutableList<T>(this, head);
}
public IEnumerable<ImmutableList<T>> PowerSet()
{
if (this == Empty)
yield return this;
else
{
var powerset = Tail.PowerSet();
foreach (var set in powerset) yield return set.Push(Head);
foreach (var set in powerset) yield return set;
}
}
}
Same algorithm SergeyS mention using Linq (where inputSet is the input and outputPowerSet is the output):
int setLength = inputSet.Count;
int powerSetLength = 1 << setLength;
for (int bitMask = 0; bitMask < powerSetLength; bitMask++)
{
var subSet = from x in inputSet
where ((1 << inputSet.IndexOf(x)) & bitMask) != 0
select x;
outputPowerSet.Add(subSet.ToList());
}
Very late to the game, but why not the approach below? It seems significantly simpler than the suggestions posted here:
/*
Description for a sample set {1, 2, 2, 3}:
Step 1 - Start with {}:
{}
Step 2 - "Expand" previous set by adding 1:
{}
---
{1}
Step 3 - Expand previous set by adding the first 2:
{}
{1}
---
{2}
{1,2}
Step 4 - Expand previous set by adding the second 2:
{}
{1}
{2}
{1,2}
---
{2}
{1,2}
{2,2}
{1,2,2}
Step 5 - Expand previous set by adding 3:
{}
{1}
{2}
{1,2}
{2}
{1,2}
{2,2}
{1,2,2}
---
{3}
{1,3}
{2,3}
{1,2,3}
{2,3}
{1,2,3}
{2,2,3}
{1,2,2,3}
Total elements = 16 (i.e. 2^4), as expected.
*/
private static void PowerSet(IList<int> nums, ref IList<IList<int>> output)
{
// ToDo: validate args
output.Add(new List<int>());
ExpandSet(nums, 0, ref output);
}
private static void ExpandSet(IList<int> nums, int pos, ref IList<IList<int>> output)
{
if (pos == nums.Count)
{
return;
}
List<int> tmp;
int item = nums[pos];
for (int i = 0, n = output.Count; i < n; i++)
{
tmp = new List<int>();
tmp.AddRange(output[i]);
tmp.Add(item);
output.Add(tmp);
}
ExpandSet(nums, pos + 1, ref output);
}
I know how to do this in an ugly way, but am wondering if there is a more elegant and succinct method.
I have a string array of e-mail addresses. Assume the string array is of arbitrary length -- it could have a few items or it could have a great many items. I want to build another string consisting of say, 50 email addresses from the string array, until the end of the array, and invoke a send operation after each 50, using the string of 50 addresses in the Send() method.
The question more generally is what's the cleanest/clearest way to do this kind of thing. I have a solution that's a legacy of my VBScript learnings, but I'm betting there's a better way in C#.
You want elegant and succinct, I'll give you elegant and succinct:
var fifties = from index in Enumerable.Range(0, addresses.Length)
group addresses[index] by index/50;
foreach(var fifty in fifties)
Send(string.Join(";", fifty.ToArray());
Why mess around with all that awful looping code when you don't have to? You want to group things by fifties, then group them by fifties.
That's what the group operator is for!
UPDATE: commenter MoreCoffee asks how this works. Let's suppose we wanted to group by threes, because that's easier to type.
var threes = from index in Enumerable.Range(0, addresses.Length)
group addresses[index] by index/3;
Let's suppose that there are nine addresses, indexed zero through eight
What does this query mean?
The Enumerable.Range is a range of nine numbers starting at zero, so 0, 1, 2, 3, 4, 5, 6, 7, 8.
Range variable index takes on each of these values in turn.
We then go over each corresponding addresses[index] and assign it to a group.
What group do we assign it to? To group index/3. Integer arithmetic rounds towards zero in C#, so indexes 0, 1 and 2 become 0 when divided by 3. Indexes 3, 4, 5 become 1 when divided by 3. Indexes 6, 7, 8 become 2.
So we assign addresses[0], addresses[1] and addresses[2] to group 0, addresses[3], addresses[4] and addresses[5] to group 1, and so on.
The result of the query is a sequence of three groups, and each group is a sequence of three items.
Does that make sense?
Remember also that the result of the query expression is a query which represents this operation. It does not perform the operation until the foreach loop executes.
Seems similar to this question: Split a collection into n parts with LINQ?
A modified version of Hasan Khan's answer there should do the trick:
public static IEnumerable<IEnumerable<T>> Chunk<T>(
this IEnumerable<T> list, int chunkSize)
{
int i = 0;
var chunks = from name in list
group name by i++ / chunkSize into part
select part.AsEnumerable();
return chunks;
}
Usage example:
var addresses = new[] { "a#example.com", "b#example.org", ...... };
foreach (var chunk in Chunk(addresses, 50))
{
SendEmail(chunk.ToArray(), "Buy V14gr4");
}
It sounds like the input consists of separate email address strings in a large array, not several email address in one string, right? And in the output, each batch is a single combined string.
string[] allAddresses = GetLongArrayOfAddresses();
const int batchSize = 50;
for (int n = 0; n < allAddresses.Length; n += batchSize)
{
string batch = string.Join(";", allAddresses, n,
Math.Min(batchSize, allAddresses.Length - n));
// use batch somehow
}
Assuming you are using .NET 3.5 and C# 3, something like this should work nicely:
string[] s = new string[] {"1", "2", "3", "4"....};
for (int i = 0; i < s.Count(); i = i + 50)
{
string s = string.Join(";", s.Skip(i).Take(50).ToArray());
DoSomething(s);
}
I would just loop through the array and using StringBuilder to create the list (I'm assuming it's separated by ; like you would for email). Just send when you hit mod 50 or the end.
void Foo(string[] addresses)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < addresses.Length; i++)
{
sb.Append(addresses[i]);
if ((i + 1) % 50 == 0 || i == addresses.Length - 1)
{
Send(sb.ToString());
sb = new StringBuilder();
}
else
{
sb.Append("; ");
}
}
}
void Send(string addresses)
{
}
I think we need to have a little bit more context on what exactly this list looks like to give a definitive answer. For now I'm assuming that it's a semicolon delimeted list of email addresses. If so you can do the following to get a chunked up list.
public IEnumerable<string> DivideEmailList(string list) {
var last = 0;
var cur = list.IndexOf(';');
while ( cur >= 0 ) {
yield return list.SubString(last, cur-last);
last = cur + 1;
cur = list.IndexOf(';', last);
}
}
public IEnumerable<List<string>> ChunkEmails(string list) {
using ( var e = DivideEmailList(list).GetEnumerator() ) {
var list = new List<string>();
while ( e.MoveNext() ) {
list.Add(e.Current);
if ( list.Count == 50 ) {
yield return list;
list = new List<string>();
}
}
if ( list.Count != 0 ) {
yield return list;
}
}
}
I think this is simple and fast enough.The example below divides the long sentence into 15 parts,but you can pass batch size as parameter to make it dynamic.Here I simply divide using "/n".
private static string Concatenated(string longsentence)
{
const int batchSize = 15;
string concatanated = "";
int chanks = longsentence.Length / batchSize;
int currentIndex = 0;
while (chanks > 0)
{
var sub = longsentence.Substring(currentIndex, batchSize);
concatanated += sub + "/n";
chanks -= 1;
currentIndex += batchSize;
}
if (currentIndex < longsentence.Length)
{
int start = currentIndex;
var finalsub = longsentence.Substring(start);
concatanated += finalsub;
}
return concatanated;
}
This show result of split operation.
var parts = Concatenated(longsentence).Split(new string[] { "/n" }, StringSplitOptions.None);
Extensions methods based on Eric's answer:
public static IEnumerable<IEnumerable<T>> SplitIntoChunks<T>(this T[] source, int chunkSize)
{
var chunks = from index in Enumerable.Range(0, source.Length)
group source[index] by index / chunkSize;
return chunks;
}
public static T[][] SplitIntoArrayChunks<T>(this T[] source, int chunkSize)
{
var chunks = from index in Enumerable.Range(0, source.Length)
group source[index] by index / chunkSize;
return chunks.Select(e => e.ToArray()).ToArray();
}