Make (mostly) equal length sets - c#

Using LINQ (or morelinq), How do I divide an unknown length (but small) array into even sets with the smaller (uneven) sets at the end, but maintaining the order within each list?
var array = new int[] {1,2,3,4};
var sets = array.something(3);
Looking for a result of:
{1,2},{3},{4}
{1} -> {1},{},{}
{1,2} -> {1},{2},{}
{1,2,3} -> {1},{2},{3}
{1,2,3,4} -> {1,2},{3},{4}
{1,2,3,4,5} -> {1,2},{3,4},{5}
{1,2,3,4,5,6} -> {1,2},{3,4},{5,6}
My original code:
const int MaxPerColumn = 6;
var perColumn = (list.Count + columnCount - 1) / columnCount;
for (var col = 1; col <= columnCount; col++)
{
var items = list.Skip((col - 1) * columnCount).Take(perColumn).Pad(MaxPerColumn, "").ToList();
// DoSomething
}
which did not work, because with a list of {1,2,3,4} it created {1,2},{3,4},{}

I suggest not using Linq here, but IEnumerator<T>, not even IEnumerable<T> in the implementation:
public static IEnumerable<T[]> Something<T>(this IEnumerable<T> source, int count) {
if (null == source)
throw new ArgumentNullException("source");
else if (count <= 0)
throw new ArgumentOutOfRangeException("count");
int c = source.Count();
int size = c / count + (c % count > 0 ? 1 : 0);
int large = count - count * size + c;
using (var en = source.GetEnumerator()) {
for (int i = 0; i < count; ++i) {
T[] chunk = new T[i < large ? size : size - 1];
for (int j = 0; j < chunk.Length; ++j) {
en.MoveNext();
chunk[j] = en.Current;
}
yield return chunk;
}
}
}
....
var array = new int[] { 1, 2, 3, 4 };
string result = string.Join(", ", array
.Something(5)
.Select(item => $"[{string.Join(", ", item)}]"));
// [1], [2], [3], [4], []
Console.Write(result);

Here is a linq way
public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int count)
{
int c = source.Count();
int chunksize = c / count + (c % count > 0 ? 1 : 0);
while (source.Any())
{
yield return source.Take(chunksize);
source = source.Skip(chunksize);
}
}
Based on https://stackoverflow.com/a/6362642/215752 and https://stackoverflow.com/a/39985281/215752

Related

returns the smallest positive integer (greater than 0) that does not occur in Array

I have the following question:-
Write a function:
class Solution { public int solution(int[] A); }
that, given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A.
For example, given A = [1, 3, 6, 4, 1, 2], the function should return 5.
Given A = [1, 2, 3], the function should return 4.
Given A = [−1, −3], the function should return 1.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [−1,000,000..1,000,000].
now i tried this code:-
using System;
// you can also use other imports, for example:
// using System.Collections.Generic;
// you can write to stdout for debugging purposes, e.g.
// Console.WriteLine("this is a debug message");
class Solution
{
public int solution(int[] A)
{
// write your code in C# 6.0 with .NET 4.5 (Mono)
int n = 1;
Array.Sort(A);
for (int i = 1; i <= 100000; i++)
{
for (int i2 = 0; i2 <= A.Length - 1; i2++)
{
if (A[i2] == i)
{
n = A[i2] + 1;
break;
}
}
}
return n;
}
}
where my code worked well for these test data:-
A = [1, 2, 3]
A = [−1, −3]
while failed for this one:-
A = [1, 3, 6, 4, 1, 2] where it return 7 instead of 5.
any advice why my code failed on the 3rd test?
Thanks
using System.Linq;
int smallestNumber = Enumerable.Range(1, 100000).Except(A).Min();
I would use following approach that uses a HashSet<int> to check if a given integer is missing:
public static int? SmallestMissing(int[] A, int rangeStart = 1, int rangeEnd = 100_000)
{
HashSet<int> hs = new HashSet<int>(A);
for (int i = rangeStart; i <= rangeEnd; i++)
if(!hs.Contains(i)) return i;
return null;
}
A HashSet is a collection if unique values and it's very efficient in lookup items(complexity is O(1)). So you get a very readable and efficient algorithm at the cost of some memory.
Maybe you could optimize it by providing another algorithm in case the array is very large, you don't want to risk an OutOfMemoryException:
public static int? SmallestMissing(int[] A, int rangeStart = 1, int rangeEnd = 100_000)
{
if(A.Length > 1_000_000)
{
Array.Sort(A);
for (int i = rangeStart; i <= rangeEnd; i++)
{
int index = Array.BinarySearch(A, i);
if(index < 0) return i;
}
return null;
}
HashSet<int> hs = new HashSet<int>(A);
for (int i = rangeStart; i <= rangeEnd; i++)
if(!hs.Contains(i)) return i;
return null;
}
If you're allowed to sort the array in-place, which means modifying the input parameter value, here's a simple linear probe for the missing value (on top of the sort of course).
Here's the pseudo-code:
Sort the array
Skip all negatives and 0's at the start
Loopify the following:
Expect 1, if not found at current location return 1
Skip all 1's
Expect 2, if not found at current location return 2
Skip all 2's
Expect 3, if not found at current location return 3
Skip all 3's
... and so on for 4, 5, 6, etc. until end of array
If we get here, return currently expected value which should've been at the end
Here's the code:
public static int FirstMissingValue(int[] input)
{
Array.Sort(input);
int index = 0;
// Skip negatives
while (index < input.Length && input[index] < 1)
index++;
int expected = 1;
while (index < input.Length)
{
if (input[index] > expected)
return expected;
// Skip number and all duplicates
while (index < input.Length && input[index] == expected)
index++;
expected++;
}
return expected;
}
Test-cases:
Console.WriteLine(FirstMissingValue(new[] { 1, 3, 6, 4, 1, 2 }));
Console.WriteLine(FirstMissingValue(new[] { 1, 2, 3 }));
Console.WriteLine(FirstMissingValue(new[] { -1, -3 }));
output:
5
4
1
Your alg won't work in case input array becomes like this: [1,2-1,1,3,5]. I did this based on your alg. Give it a try:
int[] a = new int[] { -1, -2};
IEnumerable<int> uniqueItems = a.Distinct<int>().Where(x => x > 0);
if (uniqueItems.Count() == 0)
{
Console.WriteLine("result: 1");
}
else
{
Array asList = uniqueItems.ToArray();
Array.Sort(asList);
for (int i = 1; i <= 100000; i++)
{
if ((int)asList.GetValue(i - 1) != i)
{
Console.WriteLine("result: " + i);
break;
}
}
}
you can try like this.
public static int solution(int[] A)
{
int smallest = -1;
Array.Sort(A);
if(A[0] > 1)
return 1;
for(int i = 0; i < A.Length; i++)
{
if(A.Length != i+1 && A[i] + 1 != A[i + 1] && A[i+1] > 0)
{
smallest = A[i]+1;
break;
}
else if(A[i] > 0 && A.Length == i+1)
{
smallest = A[i] + 1;
}
}
return smallest > 0 ? smallest:1;
}
Here's the approach that uses O(N) partitioning followed by an O(N) search. This approach does not use any additional storage, but it DOES change the contents of the array.
This code was converted from here. Also see this article.
I've added comments to try to explain how the second stage findSmallestMissing() works. I've not commented the partitioning method, since that's just a variant of a standard partition as might be used in a QuickSort algorithm.
static class Program
{
public static void Main()
{
Console.WriteLine(FindSmallestMissing(1, 3, 6, 4, 1, 2));
Console.WriteLine(FindSmallestMissing(1, 2, 3));
Console.WriteLine(FindSmallestMissing(-1, -3));
}
public static int FindSmallestMissing(params int[] array)
{
return findSmallestMissing(array, partition(array));
}
// Places all the values > 0 before any values <= 0,
// and returns the index of the first value <= 0.
// The values are unordered.
static int partition(int[] arr)
{
void swap(int x, int y)
{
var temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
int pIndex = 0; // Index of pivot.
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] > 0) // pivot is 0, hence "> 0"
swap(i, pIndex++);
}
return pIndex;
}
// This is the clever bit.
// We will use the +ve values in the array as flags to indicate that the number equal to that index is
// present in the array, by making the value negative if it is found in the array.
// This way we can store both the original number AND whether or not the number equal to that index is present
// in a single value.
//
// Given n numbers that are all > 0, find the smallest missing number as follows:
//
// For each array index i in (0..n):
// val = |arr[i]| - 1; // Subtract 1 so val will be between 0 and max +ve value in original array.
// if (val is in range) // If val beyond the end of the array we can ignore it
// and arr[val] is non-negative // If already negative, no need to make it negative.
// make arr[val] negative
//
// After that stage, we just need to find the first positive number in the array, which indicates that
// the number equal to that index + 1 is missing.
// n = number of values at the start of the array that are > 0
static int findSmallestMissing(int[] arr, int n)
{
for (int i = 0; i < n; i++)
{
int val = Math.Abs(arr[i]) - 1;
if (val < n && arr[val] >= 0)
arr[val] = -arr[val];
}
for (int i = 0; i < n; i++)
{
if (arr[i] > 0) // Missing number found.
return i + 1;
}
return n + 1; // No missing number found.
}
}
class Program
{
static void Main(string[] args)
{
int [] A = new int[] {1, 2, 3};
int n = 0;
bool found = false;
Array.Sort(A);
for (int i = 1; i <= 100000; i++) {
for (int x = 0; x <= A.Length - 1; x++) {
int next = (x + 1) < A.Length ? (x + 1): x;
if (A[x] > 0 && (A[next] - A[x]) > 0) {
n = A[x] + 1;
found = true;
break;
}
}
if(found) {
break;
}
}
Console.WriteLine("Smallest number: " + n);
}
}
int smallestNumber=Enumerable.Range(1,(int.Parse(A.Length.ToString())+1)).Except(A).Min();
Array.Sort(A);
for (int number = 1; number <= 100000; number++)
{
for (int num = number; i2 <= A.Length - 1; num++)
{
if (A[num] == number)
{
smallestNumber = A[num] + 1;
break;
}
}
}
return smallestNumber;
}
The easiest one :)
class Solution
{
public int solution(int[] array)
{
int[] onlyPositiveArray = array.Where(a => a > 0).OrderBy(a => a).Distinct().ToArray();
int smallestNumber = 1;
foreach (var number in onlyPositiveArray)
{
if (smallestNumber != number)
{
break;
}
smallestNumber ++;
}
if (!onlyPositiveArray.Contains(smallestNumber ))
{
return smallestNumber;
}
else
{
return smallestNumber + 1;
}
}
}
PHP Solution:
function solution($A) {
// write your code in PHP7.0
// sort array
sort($A);
// get the first
$smallest = $A[0];
// write while
while( in_array(($smallest),$A) || (($smallest) < 1 ) )
{
$smallest++;
}
return $smallest;
}
My solution, also if someone could test how performant it is?
public int solution(int[] N) {
if (N.Length == 0)
return 1;
else if (N.Length == 1)
return N[0] >= 0 ? N[0] + 1 : 1;
Array.Sort(N);
int min = Array.Find(N, IsUnderZero);
if (min ==
default)
return 1;
HashSet < int > hashSet = new HashSet < int > (N);
int max = N[N.Length - 1];
for (int i = min + 1; i <= max + 1; i++) {
if (!hashSet.Contains(i) && i > 0)
return i;
}
return max + 1;
bool IsUnderZero(int i) => i <= 0;
}
Try the below:
public static int MinIntegerGreaterThanZeroInArray(int[] A)
{
int minInt;
if (A.Length > 0)
{
Array.Sort(A);
for (minInt = 1; minInt <= A.Length; minInt++)
{
int index = Array.BinarySearch(A, minInt);
if (index < 0) return minInt;
}
return minInt;
}
//Array is empty.
throw new InvalidOperationException();
}
public static int Smallest(int[] A)
{
int maxPositiveInt = 1;
HashSet<int> NumDic = new HashSet<int>();
for (int i = 0; i < A.Length; i++)
{
if (A[i] <= 0)
{
continue;
}
if (!NumDic.Contains(A[i]))
{
NumDic.Add(A[i]);
}
maxPositiveInt = Math.Max(A[i], maxPositiveInt);
}
//All numbers are negative
if (NumDic.Count == 0)
{
return 1;
}
int smallestinteger = 1;
for (int i = 0; i < A.Length; i++)
{
if (A[i] <= 0)
{
continue;
}
if (!NumDic.Contains(smallestinteger))
{
return smallestinteger;
}
else
{
smallestinteger++;
}
}
return maxPositiveInt + 1;
}
static void Main(string[] args)
{
Console.WriteLine(solution(new int[]{1, 3, 6, 4, 1, 2}));
}
public static int solution(int[] A)
{
Array.Sort(A);
int smallest = A[0];
while (A.Contains(smallest+1)|| (smallest+1)<1)
{
smallest++;
}
return smallest +1;
}

Order an array in a specific order

I have this array of integers:-
int[] numbers = new int[] { 10, 20, 30, 40 };
I am trying to create an array which will have first element, last element, second element, second-last element and so on..
So, my resulting output will be:-
int[] result = {10,40,20,30};
This was my approach, in one loop start from first and go till the middle & in second loop start from last and get to the middle and select items accordingly, but I totally messed it up. Here is my attempted code:-
private static IEnumerable<int> OrderedArray(int[] numbers)
{
bool takeFirst = true;
if (takeFirst)
{
takeFirst = false;
for (int i = 0; i < numbers.Length / 2; i++)
{
yield return numbers[i];
}
}
else
{
takeFirst = true;
for (int j = numbers.Length; j < numbers.Length / 2; j--)
{
yield return numbers[j];
}
}
}
Need Help.
You might try this:
int[] result = numbers.Zip(numbers.Reverse(), (n1,n2) => new[] {n1, n2})
.SelectMany(x =>x)
.Take(numbers.Length)
.ToArray();
Explanation: This approach basically pairs up the elements of the original collection with the elements of its reverse ordered collection (using Zip). So you get a collection of pairs like [first, last], [second, second from last], etc.
It then flattens those collection of pairs into a single collection (using SelectMany). So the collection becomes [first, last, second, second from last,...].
Finally, we limit the number of elements to the length of the original array (n). Since we are iterating through twice as many elements (normal and reverse), it works out that iterating through n elements allow us to stop in the middle of the collection.
As a different approach, this is a modification on your existing method:
private static IEnumerable<int> OrderedArray(int[] numbers)
{
var count = (numbers.Length + 1) / 2;
for (int i = 0; i < count; i++)
{
yield return numbers[i];
int reverseIdx = numbers.Length - 1 - i;
if(i != reverseIdx)
yield return numbers[reverseIdx];
}
}
ok,
public static class Extensions
{
public static IEnumerable<T> EndToEnd<T>(this IReadOnlyList<T> source)
{
var length = source.Count;
var limit = length / 2;
for (var i = 0; i < limit; i++)
{
yield return source[i];
yield return source[length - i - 1];
}
if (length % 2 > 0)
{
yield return source[limit];
}
}
}
Which you could use like this,
var result = numbers.EndToEnd().ToArray();
more optimally,
public static class Extensions
{
public static IEnumerable<T> EndToEnd<T>(this IReadOnlyList<T> source)
{
var c = source.Count;
for (int i = 0, f = 0, l = c - 1; i < c; i++, f++, l--)
{
yield return source[f];
if (++i == c)
{
break;
}
yield return source[l];
}
}
}
no divide or modulus required.
With a simple for;
int len = numbers.Length;
int[] result = new int[len];
for (int i = 0, f = 0, l = len - 1; i < len; f++, l--)
{
result[i++] = numbers[f];
if (f != l)
result[i++] = numbers[l];
}
Based on Selman22's now deleted answer:
int[] numbers = new int[] { 10, 20, 30, 40 };
int[] result = numbers
.Select((x,idx) => idx % 2 == 0
? numbers[idx/2]
: numbers[numbers.Length - 1 -idx/2])
.ToArray();
result.Dump();
(The last line is LinqPad's way of outputting the results)
Or in less LINQy form as suggested by Jeppe Stig Nielsen
var result = new int[numbers.Length];
for (var idx = 0; idx < result.Length; idx++) {
result[idx] = idx % 2 == 0 ? numbers[idx/2] : numbers[numbers.Length - 1 -idx/2];
}
The principle is that you have two sequences, one for even elements (in the result) and one for odd. The even numbers count the first half of the array and the odds count the second half from the back.
The only modification to Selman's code is adding the /2 to the indexes to keep it counting one by one in the right half while the output index (which is what idx basically is in this case) counts on.
Came up with this
static void Main(string[] args)
{
List<int> numbers = new List<int>() { 10, 20, 30, 40, 50, 60, 70};
List<int> numbers2 = new List<int>();
int counter1 = 0;
int counter2 = numbers.Count - 1;
int remainder = numbers.Count % 2 == 0 ? 1: 0;
while (counter1-1 < counter2)
{
if (counter1 + counter2 % 2 == remainder)
{
numbers2.Add(numbers[counter1]);
counter1++;
}
else
{
numbers2.Add(numbers[counter2]);
counter2--;
}
}
string s = "";
for(int a = 0; a< numbers2.Count;a++)
s+=numbers2[a] + " ";
Console.Write(s);
Console.ReadLine();
}
This late answer steals a lot from the existing answers!
The idea is to allocate the entire result array at once (since its length is known). Then fill out all even-indexed members first, from one end of source. And finally fill out odd-numbered entries from the back end of source.
public static TElement[] EndToEnd<TElement>(this IReadOnlyList<TElement> source)
{
var count = source.Count;
var result = new TElement[count];
for (var i = 0; i < (count + 1) / 2; i++)
result[2 * i] = source[i];
for (var i = 1; i <= count / 2; i++)
result[2 * i - 1] = source[count - i];
return result;
}
Came up with this
public int[] OrderedArray(int[] numbers)
{
int[] final = new int[numbers.Length];
var limit=numbers.Length;
int last = numbers.Length - 1;
var finalCounter = 0;
for (int i = 0; finalCounter < numbers.Length; i++)
{
final[finalCounter] = numbers[i];
final[((finalCounter + 1) >= limit ? limit - 1 : (finalCounter + 1))] = numbers[last];
finalCounter += 2;
last--;
}
return final;
}

Clean algorithm to generate all sets of the kind (0) to (0,1,2,3,4,5,6,7,8,9)

Basically, I'd like a set of sets that contains from (0..9), then (0, 1..9), (1, 2..9)..(8,9), and so on and so forth up until (0,1,2,3,4,5,6,7,8,9). I know this can be accomplished by nesting for loops in the manner below, but I'm wondering if there's a neater way of doing it?
Preferably something that could be accomplished within C#, but I'm interested in any algorithm.
for (int i = 0; i < max; i++) {
yield {i};
for (int j = i + 1; j < max; j++) {
yield {i, j};
for (int k = j + 1; k < max; k++) {
yield {i, j, k};
for (int l = k + 1; l < max; l++) {
yield {i, j, k, l};
for (int m = l + 1; m < max; m++) {
yield {i, j, k, l, m};
// And so on and so forth
}
}
}
}
}
I wrote this a while ago. It uses a Stack. It's generic, so it can be used for other sequences as well.
static IEnumerable<T[]> CombinationsAnyLength<T>(params T[] values)
{
Stack<int> stack = new Stack<int>(values.Length);
int i = 0;
while (stack.Count > 0 || i < values.Length) {
if (i < values.Length) {
stack.Push(i++);
int c = stack.Count;
T[] result = new T[c];
foreach (var index in stack) result[--c] = values[index];
yield return result;
} else {
i = stack.Pop() + 1;
if (stack.Count > 0) i = stack.Pop() + 1;
}
}
}
CombinationsAnyLength(1, 2, 3, 4) outputs:
1
12
123
1234
124
13
134
14
2
23
234
24
3
34
4
Why not treat this as bits and generate the set from the bits?
IEnumberable<List<int>> MakeSets()
{
// count from 1 to 2^10 - 1 (if you want the empty set, start at 0
for (uint i=1; i < (1 << 10); i++) {
// enumerate the bits as elements in a set
List<int> set = BitsIn(i);
yield return set;
}
}
List<int> MakeSet(uint i)
{
List<int> set = new List<int>();
// this will give you values from 0..max
// if you want 1, start with 1
// if you want non-integers, pass in an array of values and index into that
int val = 0;
// for every bit in i
while (i != 0)
{
// add the val if the corresponding bit is set
if ((i & 1) != 0) set.Add(val);
i = i >> 1;
val++;
}
return set;
}
and since I like the generic version above, let's make this generic too:
IEnumerable<List<T>> MakeSets(params T[] values)
{
if (values.Length > 63) throw new IllegalArgumentException("63 is the limit");
for (ulong i = i; i < (1 << (values.Length + 1); i++) {
List<T> set = new List<T>();
int val = 0;
ulong j = i;
while (j != 0) {
if ((j & 1) != 0) set.Add(values[val]);
j = j >> 1;
val++;
}
yield return set;
}
}
here is a algorithm for generating sub-sets.
let you have a set S = [a,b,c,d,e,f].
and you want to generate all the subsets then length of the array containing all the sub-sets will be
2^n where n is number of elements in S.
int A = [] // array containing all sub-sets
for i = 0 --- 2^n
x = binary(i) // like for i = 5 -> x = '000101' where x is a string of n digits.
ns = [] // new array
for j = 0 --- n
if x[j] == '1'
push S[j] into ns array
push ns into A
return A
A will have every set you wanted or you can modify it to get new result.
Using Dennis signature:
public static IEnumerable<T[]> CombinationsAnyLength<T>(params T[] values)
{
for(var i = 0; i < (1 << values.Length); i++)
{
var result = new List<T>();
for(var j = 0; j < values.Length; j++)
{
if(((1 << j) & i) != 0)
{
result.Add(values[j]);
}
}
yield return result.ToArray();
}
}

How do you go through two int arrays and sum their values if they exist

I want to create a method that I can send two arrays (that will be containing ints). These arrays wont necessarily be equally long. for example first array could have an index of 15 while the second array has an index of 12. in that case I want to add array1 and array2 for the first 12 then just get the value of array1 for the last 3.
I thought something like this:
int[] ArrTotal(int[] array1, int[] array2)
{
int[] total = new int[15];
for (int i = 0; i < 15; i++)
{
if (array1[i] != null && array2[i] != null)
{
total[i] = array1[i] + array2[i];
}
else if(array1[i] != null)
{
total[i] = array1[i];
}
else if (array2[i] != null)
{
total[i] = array2[i];
}
else
{
total[i] = 0;
}
}
return total;
}
Problem is that I can't check and see if an int array is null. I read something about doing an:
If(i < array1.Length)
but that does not seem to work either, it says it will always be true in my case.
Am I on the right track at all or is there some major flaw I'm missing? :)
How about:
int[] ArrTotal(int[] a, int[] b)
{
if (a == null || b == null)
{
return (int[])(a ?? b).Clone();
}
int length = Math.Max(a.Length, b.Length);
int[] result = new int[length];
for (int i = 0; i < length; i++)
{
int sum = 0;
if (a.Length > i) sum += a[i];
if (b.Length > i) sum += b[i];
result[i] = sum;
}
return result;
}
Try to check lengths of both arrays before:
int length = (array1.Length < array2.Length ? array1.Length : array2.Length);
Then iterate and assign only to array indeces from 0 to length of the shorter array - 1:
for (int i = 0; i < 15; i++)
if (i < length)
newArray[i] = array1[i] + array2[i];
else
newArray[i] = 0;
int[] a1 = new int[] { 1, 2, 3, 2, 3, 1 };
int[] a2 = new int[] { 1, 2, 3, 2, 3, 1, 3, 2, 3 };
List<int> r = new List<int>();
bool a1_longer = (a1.Length > a2.Length);
int length_diff = Math.Abs(a1.Length - a2.Length);
int length = (a1_longer ? a2.Length : a1.Length);
for (int i = 0; i < length; i++) r.Add(a1[i] + a2[i]);
for (int i = 0; i < length_diff; i++) {
r.Add(a1_longer ? a1[length + i] : a2[length+i]);
}
r.ToArray();
You may use Linq for it:
int[] ArrTotal(int[] array1, int[] array2)
{
return Enumerable.Repeat(0, Math.Max(array1.Length,array2.Length))
.Select((a, index) => a +
((array1.Length > index) ? array1[index] : 0)+
((array2.Length > index) ? array2[index] : 0))
.ToArray();
}
Using Linq you can do this (which will handle null arrays). You will need a using System.Linq at the top of the source code file:
int[] ArrTotal(int[] array1, int[] array2)
{
if ((array1 == null) && (array2 == null))
return new int[0]; // Zero length array - put some other number here if you need!
else if (array1 == null)
return (int[])array2.Clone(); // Result will just be a copy of the non-null array.
else if (array2 == null)
return (int[]) array1.Clone(); // Result will just be a copy of the non-null array.
else
{
int skip = Math.Min(array1.Length, array2.Length);
return Enumerable
.Zip(array1, array2, (i1, i2) => i1 + i2)
.Concat(array1.Skip(skip))
.Concat(array2.Skip(skip))
.ToArray();
}
}

How can a large Array be split into smaller arrays?

Given a large array how can it be split into smaller arrays with the size of the smaller arrays specified as an argument of the method?
For instance, given numbers, what would Split's implementation be?
int[] numbers = new int[7845];
int[][] sectionedNumbers = numbers.Split(1000);
sectionedNumbers.Length; //outputs 8
sectionedNumbers[7].Length; //outputs 845
You can do it with an extension method:
using System;
static class Program
{
static T[][] Split<T>(this T[] arrayIn, int length)
{
bool even = arrayIn.Length%length == 0;
int totalLength = arrayIn.Length/length;
if (!even)
totalLength++;
T[][] newArray = new T[totalLength][];
for (int i = 0; i < totalLength;++i )
{
int allocLength = length;
if (!even && i == totalLength - 1)
allocLength = arrayIn.Length % length;
newArray[i] = new T[allocLength];
Array.Copy(arrayIn, i * length, newArray[i], 0, allocLength);
}
return newArray;
}
static void Main(string[] args)
{
int[] numbers = new int[8010];
for (int i = 0; i < numbers.Length; ++i)
numbers[i] = i;
int[][] sectionedNumbers = numbers.Split(1000);
Console.WriteLine("{0}", sectionedNumbers.Length);
Console.WriteLine("{0}", sectionedNumbers[7].Length);
Console.WriteLine("{0}", sectionedNumbers[1][0]);
Console.WriteLine("{0}", sectionedNumbers[7][298]);
Console.ReadKey();
}
}
This prints:
9
1000
1000
7298
This isn't necessarily a good idea, but here's an implementation that generalises this splitting operation to IEnumerable<T>, returning an IEnumerable<IEnumerable<T>>.
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> input, int size)
{
return input.Select((a, i) => new { Item = a, Index = i })
.GroupBy( b => (b.Index / size))
.Select(c => c.Select(d => d.Item));
}
Reed beat me to it, but here's my method anyway:
public int[][] Split(int[] source, int size)
{
int fullArrayCount = source.Length / size;
int totalArrayCount = fullArrayCount;
int remainder = source.Length - (fullArrayCount * size);
if (remainder > 0)
{
totalArrayCount++;
}
int[][] output = new int[totalArrayCount][];
for (int i = 0; i < fullArrayCount; i++)
{
output[i] = new int[size];
Array.Copy(source, i * size, output[i], 0, size);
}
if (totalArrayCount != fullArrayCount)
{
output[fullArrayCount] = new int[remainder];
Array.Copy(source, fullArrayCount * size,
output[fullArrayCount], 0, remainder);
}
return output;
}

Categories

Resources