Split number into equal sized groups - c#

Using this example:
var amount = x;
var maxPerGroup = y;
var amountGroups = Ceiling(amount/maxPerGroup);
Can someone help me how to split the Amount into AmountGroups with a max amount per group of maxAmount?
These groups have to be almost the same size.
For example:
amount = 45;
maxPerGroup = 15;
amountGroups = 3;
Result: 15 15 15
I am using C# as language.
Thanks in advance!

number of groups := ceiling(total / max group size)
number per group := floor(total / number of groups)
rem = total % number per group
You will have rem groups with number per group + 1 and number of groups - rem groups with number per group.
EDIT: Example:
total := 50
max group size := 15
number of groups := ceiling(50 / 15) // 4
number per group := floor(50 / 4) // 12
rem := 50 % 12 // 2
2 groups with 13 and 2 with 12.

There are many ways of splitting the amount between groups. It all depends on whether the only factor is the number of groups or if there are any other factors. See:
static void Main(string[] args)
{
List<int> list1 = Split1(48, 15); // result is: 15, 15, 15, 3
List<int> list2 = Split2(48, 15); // result is 12, 12, 12, 12
}
public static List<int> Split1 (int amount, int maxPerGroup)
{
int amountGroups = amount / maxPerGroup;
if (amountGroups * maxPerGroup < amount)
{
amountGroups++;
}
List<int> result = new List<int>();
for (int i = 0; i < amountGroups; i++)
{
result.Add(Math.Min(maxPerGroup, amount));
amount -= Math.Min(maxPerGroup, amount);
}
return result;
}
public static List<int> Split2 (int amount, int maxPerGroup)
{
int amountGroups = amount / maxPerGroup;
if (amountGroups * maxPerGroup < amount)
{
amountGroups++;
}
int groupsLeft = amountGroups;
List<int> result = new List<int>();
while (amount > 0)
{
int nextGroupValue = amount / groupsLeft;
if (nextGroupValue * groupsLeft < amount)
{
nextGroupValue++;
}
result.Add(nextGroupValue);
groupsLeft--;
amount -= nextGroupValue;
}
return result;
}

NOTE
not exact c# just to give you the idea.
I think you are looking for a way to grammatically divide a number in different groups. Without knowing how big the groups are and a random amount of groups.
so let's say x = 30 y = 15. 30/15 = 3 groups of 15 and let's say x= 43 so the number should be like ? 14 14 15
groups (since you already have this calculated correctly)(should be a double)
// maxPerGroup = y
membersPerGroup = floor(amount/groups)
List a = new List
//Is the leftover value of the modulus
leftover = amount%groups;
//Loops for each group
for(int i=0;i<groups;i++){
//If there is a left over value
if(leftover>0){
a.Add(membersPerGroup +1);
leftover--;
}else{
a.Add(membersPerGroup );
}
}
I could write in proper c# but It seems that you found the proper code for it

simple non-optimized solution:
int i = amount;
int j = 0;
int [] groups = new int[amountGroups];
while(i > 0) {
groups[j] += 1;
i--;
j = (j+1)%amountGroups;
}

private static int[] DistributeIntoGroups(int sum, int groupsCount)
{
var baseCount = sum / groupsCount;
var leftover = sum % groupsCount;
var groups = new int[groupsCount];
for (var i = 0; i < groupsCount; i++)
{
groups[i] = baseCount;
if (leftover > 0)
{
groups[i]++;
leftover--;
}
}
return groups;
}

// For separating a collection into ranges
static List<List<T>> Split<T>(List<T> source, int size)
{
// TODO: Prepopulate with the right capacity
List<List<T>> ret = new List<List<T>>();
for (int i = 0; i < source.Count; i += size)
{
ret.Add(source.GetRange(i, Math.Min(size, source.Count - i)));
}
return ret;
}
// For separating an int into a Tuple range
static List<Tuple<int, int>> Split(int source, int size)
{
var ret = new List<Tuple<int, int>>();
for (int i = 0; i < source; i += size)
{
ret.Add(new Tuple<int, int>(i, (i + Math.Min(size, source - i))));
}
return ret;
}

Divide an integer into groups
public class Program
{
static void Main(string[] args)
{
List<int> results = DistributeInteger(20, 3).ToList();//output: 7,7,6
foreach (var result in results)
{
Console.WriteLine(result);
}
Console.Read();
}
public static IEnumerable<int> DistributeInteger(int total, int divider)
{
if (divider == 0)
yield return 0;
int rest = total % divider;
double result = total / (double)divider;
for (int i = 0; i < divider; i++)
{
if (rest-- > 0)
yield return (int)Math.Ceiling(result);
else
yield return (int)Math.Floor(result);
}
}
}

private void button2_Click(object sender, EventArgs e)
{
// I wanted to get count from a datagridview (x)
// and then split into groups based on the
// count from a combobox (n). In my example my
// grid had 1771 rows and was split into: 25 groups
// (4x of 70 and 21x of 71)
// Driver code
int x = myDataGridView.Rows.Count; //1771
int n = assemblies_cmbbox.Items.Count; //25
split(x, n);
//split(amount, maxPerGroup);
}
// Function that prints
// the required sequence
private void split(int x, int n)
{
// If we cannot split the
// number into exactly 'N' parts
if (x < n)
Debug.WriteLine("-1 ");
// If x % n == 0 then the minimum
// difference is 0 and all
// numbers are x / n
else if (x % n == 0)
{
for (int i = 0; i < n; i++)
Debug.WriteLine((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)
Debug.WriteLine((pp + 1) + " ");
else
Debug.WriteLine(pp + " ");
}
}
}
All credits to Sachin.
Visit https://www.geeksforgeeks.org/split-the-number-into-n-parts-such-that-difference-between-the-smallest-and-the-largest-part-is-minimum/

int amount = x;
int maxPerGroup = y;
int amountGroups = new int[Ceiling(amount/maxPerGroup)];
for(int i=0; i<maxPerGroup; i++)
{
if(x>maxPerGroup)
{
amountGroups[i]= maxPerGroup;
x = x-maxPerGroup;
}
else
{
amountGroups[i] = x;
x =0;
}
}

Related

Returns incorrect output

Description of challenge:
Have the function KaprekarsConstant(num) take the num parameter being passed which will be a 4-digit number with at least two distinct digits.
Your program should perform the following routine on the number:
Arrange the digits in descending order and in ascending order (adding
zeroes to fit it to a 4-digit number), and subtract the smaller
number from the bigger number. Then repeat the previous step.
Performing this routine will always cause you to reach a fixed number: 6174.
Then performing the routine on 6174 will always give you 6174 (7641 - 1467 = 6174).
Your program should return the number of times this routine must be performed until 6174 is reached.
For example: if num is 3524 your program should return 3 because of the following steps:
5432 - 2345 = 3087
8730 - 0378 = 8352
8532 - 2358 = 6174
Web-site where I took this challenge Coderbyte
Problem :
All works correctly until returning the result in Foo() I don't know why but it calls this function some times until Count==2
Please help.Sorry please if I made mistakes and my code is really bad because I am schooler(9 Grade) and I have been programming for half a year
using System;
class MainClass
{
public static int Foo(int num,int Counter)
{
int Count = Counter;
int[] arr = new int[4];
arr[0] = num / 1000;
arr[1] = num % 10;
arr[2] = (num / 100) % 10;
arr[3] = (num % 100) / 10;
Array.Sort(arr);
int[] AscArr = new int[4];
arr.CopyTo(AscArr, 0);
Array.Reverse(arr);
int[] DescArr = arr;
int sub = 0;
string AscStr = string.Empty;
string DescStr = string.Empty;
for (int i = 0; i < AscArr.Length; i++)
{
AscStr += AscArr[i];
}
for (int i = 0; i < DescArr.Length; i++)
{
DescStr += DescArr[i];
}
int b = int.Parse(AscStr);
int a = int.Parse(DescStr);
sub = a - b;
if (sub!=6174)
{
Count++;
Foo(sub,Count);
}
if (sub==6174)
{
Count++;
}
return Count;
}
public static int KaprekarsConstant(int num)
{
int[] arr=new int[4];
arr[0] = num / 1000;
arr[1] = num % 10;
arr[2] = (num / 100) % 10;
arr[3] = (num % 100) / 10;
Array.Sort(arr);
int[] AscArr=new int[4];
arr.CopyTo(AscArr,0);
Array.Reverse(arr);
int[] DescArr = arr;
int sub = 0 ;
string AscStr=string.Empty;
string DescStr = string.Empty;
for (int i = 0; i < AscArr.Length; i++)
{
AscStr += AscArr[i];
}
for (int i = 0; i < DescArr.Length; i++)
{
DescStr += DescArr[i];
}
int b = int.Parse(AscStr);
int a = int.Parse(DescStr);
sub = a - b;
int Counter =1;
int Count=0;
if (Count!=6174)
{
Count = Foo(sub, Counter);
}
return Count;
}
static void Main()
{
// keep this function call here
Console.WriteLine(KaprekarsConstant(int.Parse(Console.ReadLine())));
}
}
Your code is too much complex, plus, your way of dividing number to array is giving wrong results.
// this is wrong you can print array, the numbers goes into wrong indexes
arr[0] = num / 1000;
arr[1] = num % 10;
arr[2] = (num / 100) % 10;
arr[3] = (num % 100) / 10;
Use this:
using System;
class MainClass
{
public static int count = 0;
public static void KaprekarsConstant(int num)
{
if (num == 6174) // base case
return;
count++;
string[] Aarr=new string[4];
string[] Darr = new string[4];
string asc = "", dsc = "";
Aarr[3] = (num % 10).ToString();
Darr[3] = (num % 10).ToString();
num /= 10;
Aarr[2] =(num % 10).ToString();
Darr[2] = (num % 10).ToString();
num /= 10;
Aarr[1] = (num % 10).ToString();
Darr[1] = (num % 10).ToString();
num /= 10;
Aarr[0] =(num % 10).ToString();
Darr[0] = (num % 10).ToString();
Array.Sort(Aarr); // ascneding sorted
Array.Sort<string>(Darr, new Comparison<string>( (i1, i2) => i2.CompareTo(i1))); // descending sorted
for(int i = 0; i< 4;i++)
{
asc += Aarr[i];
dsc += Darr[i];
}
KaprekarsConstant(Convert.ToInt32(dsc) -Convert.ToInt32(asc) );
}
static void Main()
{
KaprekarsConstant(int.Parse(Console.ReadLine()));
Console.WriteLine("\nIt took "+count + "times to reach 6174");
}
}

Find 2nd lowest digit from integer without using any array and functions in c#?

If i have 478523698 as an integer number, how to find 2nd lowest number only with if conditions wihout converting it to string, this question was asked in interview. I got the output by converting Integer to array like this
`
int integer=478523698;
//converting integer to array
string s,numbers = integer.ToString();
char[] num = numbers.ToCharArray();
int L=num.Length;
int[] intArray = new int[L];
for (int i = 0; i <L; i++)
{
s = num[i].ToString();
intArray[i] = Convert.ToInt32(s);
}
//code for getting 2nd lowest number
int min1=intArray[0];
int min2=0;
if (min2 < min1)
{
min1 = intArray[1];
min2 = intArray[0];
}
for(var i=0;i<=intArray.Length-1;i++){
if (intArray[i] < min1)
{
min2 = min1;
min1 = intArray[i];
}
else if (intArray[i] < min2)
{
min2 = intArray[i];
}
}
Console.Write("Second Lowest Number is {0} ",min2); `
I think you can do this without converting to string, and with a simple loop and conditions like the following:
int inputInteger = 478523698;
int numberSample = inputInteger;
int lowest = int.MaxValue, secondlowest = int.MaxValue;
while (numberSample != 0)
{
int digit = numberSample % 10;
numberSample = numberSample / 10;
if (digit < secondlowest && digit!=lowest)
{
secondlowest = digit;
}
if (secondlowest < lowest)
{
int temp = secondlowest;
secondlowest = lowest;
lowest = temp;
}
}
if (secondlowest == int.MaxValue)
{
Console.WriteLine("There is no second lowest number");
}
else
{
Console.WriteLine("Lowest digit in {0} is {1} and second lowest digit is {2}", inputInteger,lowest,secondlowest);
}
Working example, you can see that above code will print the output as Lowest digit in 478523698 is 2 and the second-lowest digit is 3, if you initialize inputInteger with 222 means the output will be There is no second-lowest number
I'm sure this can be simplified but it works...
class Program
{
static void Main(string[] args)
{
var number = 478523698;
var numberList = new List<int>();
for (var i = 1; i <= number; i *= 10)
{
var currentNumber = number / i % 10;
numberList.Add(currentNumber);
}
Console.WriteLine(numberList.OrderBy(x => x).Skip(1).FirstOrDefault());
Console.Read();
}
}

Can I find the number of digits of a BigInteger in C#?

I am solving this problem, in which they ask for the index of the first Fibonacci number of 1000 digits, and my first idea was something similar to:
BigInteger x = 1;
BigInteger y = 1;
BigInteger tmp = 0;
int currentIndex = 2;
while (x.NoOfDigits < 1000)
{
tmp = x + y;
y = x;
x = tmp;
currentIndex++;
}
return currentIndex;
However, as far as I can tell, there is no method for counting the number of digits of a BigInteger. Is this true? One way of circumventing it is to use the .ToString().Length method of a BigInteger, but I'm told that string processing is slow.
A BigInteger also has a .ToByteArray(), and I thought of converting a BigInteger to a byte array and checking the length of that array - but I don't think that this uniquely determines the number of digits in the BigInteger.
For what it's worth, I implemented another way of solving it, which is manually storing the Fibonacci numbers in array, and which stops as soon as the array is full, and I compared this to the .ToString-based method, which is about 2.5 times slower, but the first method takes 0.1 second, which also seems like a long time.
Edit: I've tested the two suggestions in the answers below (the one with BigInteger.Log and the one with MaxLimitMethod). I get the following run times:
Original method: 00:00:00.0961957
StringMethod: 00:00:00.1535350
BigIntegerLogMethod: 00:00:00.0387479
MaxLimitMethod: 00:00:00.0019509
Program
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Diagnostics;
class Program
{
static void Main(string[] args)
{
Stopwatch clock = new Stopwatch();
clock.Start();
int index1 = Algorithms.IndexOfNDigits(1000);
clock.Stop();
var elapsedTime1 = clock.Elapsed;
Console.WriteLine(index1);
Console.WriteLine("Original method: {0}",elapsedTime1);
Console.ReadKey();
clock.Reset();
clock.Start();
int index2 = Algorithms.StringMethod(1000);
clock.Stop();
var elapsedTime2 = clock.Elapsed;
Console.WriteLine(index2);
Console.WriteLine("StringMethod: {0}", elapsedTime2);
Console.ReadKey();
clock.Reset();
clock.Start();
int index3 = Algorithms.BigIntegerLogMethod(1000);
clock.Stop();
var elapsedTime3 = clock.Elapsed;
Console.WriteLine(index3);
Console.WriteLine("BigIntegerLogMethod: {0}", elapsedTime3);
Console.ReadKey();
clock.Reset();
clock.Start();
int index4 = Algorithms.MaxLimitMethod(1000);
clock.Stop();
var elapsedTime4 = clock.Elapsed;
Console.WriteLine(index4);
Console.WriteLine("MaxLimitMethod: {0}", elapsedTime4);
Console.ReadKey();
}
}
static class Algorithms
{
//Find the index of the first Fibonacci number of n digits
public static int IndexOfNDigits(int n)
{
if (n == 1) return 1;
int[] firstNumber = new int[n];
int[] secondNumber = new int[n];
firstNumber[0] = 1;
secondNumber[0] = 1;
int currentIndex = 2;
while (firstNumber[n-1] == 0)
{
int carry = 0, singleSum = 0;
int[] tmp = new int[n]; //Placeholder for the sum
for (int i = 0; i<n; i++)
{
singleSum = firstNumber[i] + secondNumber[i];
if (singleSum >= 10) carry = 1;
else carry = 0;
tmp[i] += singleSum % 10;
if (tmp[i] >= 10)
{
tmp[i] = 0;
carry = 1;
}
int countCarries = 0;
while (carry == 1)
{
countCarries++;
if (tmp[i + countCarries] == 9)
{
tmp[i + countCarries] = 0;
tmp[i + countCarries + 1] += 1;
carry = 1;
}
else
{
tmp[i + countCarries] += 1;
carry = 0;
}
}
}
for (int i = 0; i < n; i++ )
{
secondNumber[i] = firstNumber[i];
firstNumber[i] = tmp[i];
}
currentIndex++;
}
return currentIndex;
}
public static int StringMethod(int n)
{
BigInteger x = 1;
BigInteger y = 1;
BigInteger tmp = 0;
int currentIndex = 2;
while (x.ToString().Length < n)
{
tmp = x + y;
y = x;
x = tmp;
currentIndex++;
}
return currentIndex;
}
public static int BigIntegerLogMethod(int n)
{
BigInteger x = 1;
BigInteger y = 1;
BigInteger tmp = 0;
int currentIndex = 2;
while (Math.Floor(BigInteger.Log10(x) + 1) < n)
{
tmp = x + y;
y = x;
x = tmp;
currentIndex++;
}
return currentIndex;
}
public static int MaxLimitMethod(int n)
{
BigInteger maxLimit = BigInteger.Pow(10, n - 1);
BigInteger x = 1;
BigInteger y = 1;
BigInteger tmp = 0;
int currentIndex = 2;
while (x.CompareTo(maxLimit) < 0)
{
tmp = x + y;
y = x;
x = tmp;
currentIndex++;
}
return currentIndex;
}
}
Provided that x > 0
int digits = (int)Math.Floor(BigInteger.Log10(x) + 1);
will get the number of digits.
Out of curiosity, I tested the
int digits = x.ToString().Length;
approach. For 100 000 000 iterations, it's 3 times slower than the Log10 solution.
Expanding on my comment--instead of testing based on number of digits, test based on exceeding a constant that has the upper limit of the problem:
public static int MaxLimitMethod(int n)
{
BigInteger maxLimit = BigInteger.Pow(10, n);
BigInteger x = 1;
BigInteger y = 1;
BigInteger tmp = 0;
int currentIndex = 2;
while (x.CompareTo(maxLimit) < 0)
{
tmp = x + y;
y = x;
x = tmp;
currentIndex++;
}
return currentIndex;
}
This should result in a significant performance increase.
UPDATE:
This is an even quicker method on .NET 5 (since GetBitLength() is required):
private static readonly double exponentConvert = Math.Log10(2);
private static readonly BigInteger _ten = 10;
public static int CountDigits(BigInteger value)
{
if (value.IsZero)
return 1;
value = BigInteger.Abs(value);
if (value.IsOne)
return 1;
long numBits = value.GetBitLength();
int base10Digits = (int)(numBits * exponentConvert).Dump();
var reference = BigInteger.Pow(_ten, base10Digits);
if (value >= reference)
base10Digits++;
return base10Digits;
}
The slowest part of this algorithm for large values is the BigInteger.Pow() operation. I have optimized the CountDigits() method in Singulink.Numerics.BigIntegerExtensions with a cache that holds powers of 10, so check that out if you are interested in the fastest possible implementation. It caches powers up to exponents of 1023 by default but if you want to trade memory usage for faster performance on even larger values you can increase the max cached exponent by calling BigIntegerPowCache.GetCache(10, maxSize) where maxSize = maxExponent + 1.
On an i7-3770 CPU, this library takes 350ms to get the digit count for 10 million BigInteger values (single-threaded) when the digit count <= the max cached exponent.
ORIGINAL ANSWER:
The accepted answer is unreliable, as indicated in the comments. This method works for all numbers:
private static int CountDigits(BigInteger value)
{
if (value.IsZero)
return 1;
value = BigInteger.Abs(value);
if (value.IsOne)
return 1;
int exp = (int)Math.Ceiling(BigInteger.Log10(value));
var test = BigInteger.Pow(10, exp);
return value >= test ? exp + 1 : exp;
}

Solving with only loop

The number 124 has the property that it is the smallest number whose first three multiples contain the digit 2. Observe that
124*1 = 124, 124*2 = 248, 124*3 = 372 and that 124, 248 and 372 each contain the digit 2. It is possible to generalize this property to be the smallest number whose first n multiples each contain the digit 2. Write a function named smallest(n) that returns the smallest number whose first n multiples contain the digit 2. Hint: use modulo base 10 arithmetic to examine digits.
Its signature is
int smallest(int n)
Examples
If n is return because
4 624 because the first four multiples of 624 are 624, 1248, 1872, 2496 and they all contain the
digit 2. Furthermore 624 is the smallest number whose first four multiples contain the digit 2.
5 624 because the first five multiples of 624 are 624, 1248, 1872, 2496, 3120. Note that 624 is also
the smallest number whose first 4 multiples contain the digit 2.
6 642 because the first five multiples of 642 are 642, 1284, 1926, 2568, 3210, 3852
7 4062 because the first five multiples of 4062 are 4062, 8124, 12186, 16248, 20310, 24372, 28434.
Note that it is okay for one of the multiples to contain the digit 2 more than once (e.g., 24372).
I tried to solve this by this way
//Its a incomplete code
public static int smallest(int n)
{
int i = 1;
for (; ; )
{
int temp = 0;
int myNum = 0;
for (int j = 1; j <= n; j++)
{
myNum = i * j;
//check for condition
}
//if condition ture break
}
}
But I am stick to the problem is I cannot create hard coded n times variable.. Can you help me proceed that?
You may assume that such a number is computable on a 32 bit machine, i.e, you do not have to detect integer overflow in your answer.
using System;
using System.Collections.Generic;
namespace firstconsoleproject
{
class MainClass
{
public static void Main (string[] args)
{
int first=4;
int c=0;
int ax;
int ai;
Console.WriteLine ("please enter n");
ax = Convert.ToInt32( Console.ReadLine());
for (int i=11 ; ax>0 ;)
{ if (first==1)
{
c = ax+1;
i++;
}
c--;
ai=i*c;
for (int ten=10 ; ; )
{
if(ai%ten==2)
{
first=0;
break;
}else if (ai==0)
{
first=1;
break;
}
ai/=10;
}
if (c==0){Console.WriteLine("number is "+i);break;}
}Console.ReadKey ();
}
}
}
// Function smallest n
public int smallest(int a)
{
int temp = 0, holder = 0, k = 0;
if (a <= 0) return 0;
else
{
for (int i = 100; i < Int16.MaxValue; i++)
{
int count = 0;
k = 0;
int[] array = new int[a];
for (int j = 1; j < 9; j++)
{
holder = i * j;
temp = holder;
while (temp > 0)
{
int rem = temp % 10;
if (rem == 2)
{
count++;
if (k < a)
{
array[k] = j;
k++;
break;
}
}
temp /= 10;
}
if (count == a)
{
int countTemp = 0;
for (int h = 0; h < a; h++)
{
if (h + 1 < a)
{
if (array[h + 1] == array[h] + 1 && array[0] == 1 && array[h] > 0)
{
countTemp++;
if (countTemp == a - 1)
return i;
}
}
}
}
}
}
}
return 0;
}
public static int smallest(int n)
{
int i = 1;
for (; ; )
{
int contain = 0;
int temp = 0;
int myNum = 0;
for (int j = 1; j <= n; j++)
{
myNum = i * j;
temp = myNum;
while (true)
{
if (temp % 10 == 2)
{
contain++;
break;
}
temp = temp / 10;
if (temp <= 0)
break;
}
}
if (contain == n)
break;
i++;
}
return i;
}

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;
}

Categories

Resources