How to write function to got new B array but put multiple 3 elements of array A..
int[] a = new int[] {1,2,3,4,5,6,7,8,9,10};
b0 = a1,a2,a3
b1 = a4,a5,a6
b2 = etc...
ONLY if you aren't allowed to use Linq...
int[] a = new int[] {1,2,3,4,5,6,7,8,9,10};
int[,] b;
if(a.Length % 3 != 0)
{
b = new int[a.Length/3+1,3];
}
else
{
b = new int[a.Length/3, 3];
}
for(int i = 0; i< a.Length;i++)
{
b[i/3,i%3] = a[i];
}
Well if you cannot use LINQ than simple for loop in an extension method can do the trick :
public static int[][] GetChunks(int[] array, int chunkSize)
{
if(array.Length < chunkSize)
{
throw new ArgumentOutOfRangeException("chunkSize");
}
var result = new List<int[]>(array.Length / chunkSize);
for (var i = 0; i < array.Length; i += chunkSize)
{
var chunk = new int[chunkSize + i < array.Length ? chunkSize : (array.Length - i - 1)];
for (var j = 0; j < chunk.Length; j++)
{
chunk[j] = array[i + j];
}
result.Add(chunk);
}
return result.ToArray();
}
Example of usage :
int[] nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[][] chunksOfFixedSize = GetChunks(nums, 3);
Console.WriteLine("Number of chunks : " + chunksOfFixedSize.Length);
Console.WriteLine("Second element at 3rd chunk is : " + chunksOfFixedSize[2][1]);
Output :
Number of chunks : 4
Second element at 3rd chunk is : 8
P.S.
If you prefer to have different variables per each array you could simply do something like :
var b = chunksOfFixedSize[0];
var c = chunksOfFixedSize[1];
var d = chunksOfFixedSize[2];
Linq solution:
int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int size = 3;
// Array of 3 items arrays
int[][] result = Enumerable
.Range(0, a.Length / size + (a.Length % size == 0 ? 0 : 1))
.Select(index => a
.Skip(index * size)
.Take(size)
.ToArray())
.ToArray(); // if you want array of 3-item arrays
Test
String report = String.Join(Environment.NewLine,
result.Select(chunk => String.Join(", ", chunk)));
// 1, 2, 3
// 4, 5, 6
// 7, 8, 9
// 10
Console.Write(report);
Here is a solution where you get the exact lengths in the arrays:
int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// if the length % 3 is zero, then it has length / 3 values
// but if it doesn't go without rest, the length of the array in the first dimention is + 1
int[][] b = new int[((a.Length % 3 == 0) ? a.Length / 3 : a.Length / 3 + 1)][];
for (int i = 0; i < b.Length; i++)
{
// the length of the second dimension of the array is the 3 if it goes throught 3
// but if it has rest, then the length is the rest
b[i] = new int[(i + 1) * 3 <= a.Length ? 3 : a.Length % 3];
int[] bTemp = new int[b[i].Length];
for (int j = 0; j < b[i].Length; j++)
{
bTemp[j] = a[i * 3 + j];
}
b[i] = bTemp;
}
And this is the result of b
The simplest and ugliest way would be
var a = new int[] {1,2,3,4,5,6,7,8,9,10};
var b0 = new int[] {a[0], a[1], a[2]};
var b1 = new int[] {a[3], a[4], a[5]};
otherwise
int[][] b = new int[a.Length][];
b[0] = a;
by the use of a two dimensional array, you can just select whatever array you want and assign it.
Related
There is a list of short. The values of it doesn't matter like:
List<short> resultTemp = new List<short>{1,2,3,4,5,6,7,8,9...};
This code should reduse the result list count by removing each Nth item from it.
Example 1:
List<short>{1,2,3,4,5,6,7,8,9,10}.Count == 10;
var targetItemsCount = 5;
result should be {1,3,5,7,9} and result.Count should be == 5
Example 2:
List<short>{1,2,3,4,5,6,7,8,9}.Count == 9;
var targetItemsCo:nt = 3;
result should be {1,4,7} and result.Count should be == 3
But it should stop to remove it, somewhere for make result count equal targetItemsCount (42 in this code, but its value else doesn't matter).
The code is:
var currentItemsCount = resultTemp.Count;
var result = new List<short>();
var targetItemsCount = 42;
var counter = 0;
var counterResettable = 0;
if (targetItemsCount < currentItemsCount)
{
var reduceIndex = (double)currentItemsCount / targetItemsCount;
foreach (var item in resultTemp)
{
if (counterResettable < reduceIndex ||
result.Count + 1 == currentItemsCount - counter)
{
result.Add(item);
counterResettable++;
}
else
{
counterResettable = 0;
}
counter++;
}
}
And the resault.Count in this example equals 41, but should be == targetItemsCount == 42;
Ho do I remove each N item in List untill List.Count more then target value with C#?
If my understanding is correct:
public static void run()
{
var inputs =
new List<Input>{
new Input{
Value = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },`
TargetCount = 5, ExpectedOutput= new List<int>{1,3,5,7,9}
},
new Input{
Value = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 },
TargetCount = 3, ExpectedOutput= new List<int>{1,4,7}
},
};
foreach (var testInput in inputs)
{
Console.WriteLine($"# Input = [{string.Join(", ", testInput.Value)}]");
var result = Reduce(testInput.Value, testInput.TargetCount);
Console.WriteLine($"# Computed Result = [{string.Join(", ", result)} ]\n");
}
}
static List<int> Reduce(List<int> input, int targetItemsCount)
{
while (input.Count() > targetItemsCount)
{
var nIndex = input.Count() / targetItemsCount;
input = input.Where((x, i) => i % nIndex == 0).ToList();
}
return input;
}
class Input
{
public List<int> ExpectedOutput;
public List<int> Value;
public int TargetCount;
}
Result :
Input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Computed Result = [1, 3, 5, 7, 9 ]
Input = [1, 2, 3, 4, 5, 6, 7, 8, 9]
Computed Result = [1, 4, 7 ]
To guarantee you get the expected number of selected items:
double increment = Convert.ToDouble(resultTemp.Count) / targetItemsCount;
List<short> result = Enumerable.Range(0, targetItemsCount).
Select(x => resultTemp[(int)(x * increment)]).
ToList();
Note that in the following case
List<short>{1,2,3,4,5,6,7,8,9}.Count == 9;
var targetItemsCount = 6;
The result will be [1, 2, 4, 5, 7, 8], i.e. rounding the index down when needed
Also, you'll need to add validation (targetItemsCount > 0, targetItemsCount < resultTemp.Count...)
Link to Fiddle
Give this a try:
var resultTemp = Enumerable.Range(1, 9).ToList();
var targetItemsCount = 3;
var roundingError = resultTemp.Count % targetItemsCount;
var reduceIndex = (resultTemp.Count - roundingError) / targetItemsCount;
List<int> result;
if (reduceIndex <= 1)
result = resultTemp.Take(targetItemsCount).ToList();
else
result = resultTemp.Where((a, index) => index % reduceIndex == 0).Take(targetItemsCount).ToList();
Tried it with your given example, also gave 42 a spin with a list of 1 to 100 it will remove every 2nd item till it reaches 42, so the last entry in the list would be 83.
As I said, give it a try and let me know if it fits your requirement.
This question already has answers here:
LINQ to find series of consecutive numbers
(6 answers)
Closed 5 years ago.
I have a List of id's (int) like
[1,2,3,5,7,8,11,13,14..]
is there a fast/smart way (linq?) to get all id's or if possible, the ranges?
The result should be like [1-3, 5, 7-8, 11, 13-14].
Sure, it's easy to loop and count the int value to get the result but I'm sure there must be a easier way to do this.
disclaimer this is very slow on big list, you should do a distinct too
this should do the trick
static void Main(string[] args)
{
//a list with a possible of duplicate
var theList = (new int[] { 1, 2, 3, 5, 7, 8, 11, 13, 14, 13 }).OrderBy(x => x).ToList();
var step1 = theList.Select((a, b) => theList.Skip(b).TakeWhile((x, y) => a == x || theList[b + y] - 1 == theList[b + y - 1]));
var step2 = step1.GroupBy(x => x.Last())
.Select(x => x.SelectMany(y => y).Distinct())
.Select(x => x.Count() > 1 ? string.Format("{0}-{1}", x.First(), x.Last()) : x.First().ToString());
var result = string.Format("[{0}]", string.Join(", ", step2));
}
Old school way with a single for loop.
try
{
List<int> i = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 };
int istart = i[0];
bool flag = false;
// Use StringBuilder
for(int index = 0;index<i.Count-1;index++)
{
if ((i[index] + 1) == i[index + 1])
{
flag = true;
continue;
}
else
{
if (!flag)
Console.Write(istart);
else
Console.Write(istart + "-" + i[index]);
Console.Write(",");
flag = false;
istart = i[index + 1];
}
}
if (istart + 1 == i[i.Count - 1])
Console.Write(istart + "-" + i[i.Count - 1]);
else
Console.WriteLine(istart);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine();
Console.WriteLine("Done");
Console.Read();
Input List<int> i = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 };
Input List<int> i = new List<int>() { 1, 2, 3, 4, 5, 7, 8, 11, 13, 13 };
Input List<int> i = new List<int>() { 1, 4, 5, 7, 8, 9, 2, 13, 15, 17 };
Considering a ordered list and unique ids, I think the simplest approach is to use classic for and while
List<int> ids = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 };
int i = 0;
bool isrange;
for(i=0;i<ids.Count;i++)
{
isrange = false;
Console.Write(ids[i]);
while (i < ids.Count-1 && ids[i + 1] == ids[i] + 1)
{
i++;
isrange = true;
}
if (isrange)
Console.Write("-" + ids[i]);
if (!(i + 1 == ids.Count))
Console.Write(",");
}
There is a linq way to do it (if numbers do not repeat), but I am not sure if it is easier:
int last = -1;
int rank = 0;
IEnumerable<string> grouped = arr
.GroupBy(i =>
{
rank += i - last - 1;
last = i;
return rank;
})
.Select(g => g.Count() == 1 ? g.First().ToString()
: g.First().ToString() + "-" + g.Last().ToString());
It seems rather complicated to me, more resource intensive than necessary and not flexible. Linq is great for many cases, but sometimes it just does not fit well. Simple loop is sometimes the best you can get:
IEnumerable<string> Group(IEnumerable<int> sortedArr)
{
using (var en = sortedArr.GetEnumerator())
{
if (!en.MoveNext())
{
yield break;
}
int first = en.Current;
int last = first;
int count = 1;
while (true)
{
bool end;
if ((end = !en.MoveNext()) || en.Current - last > 1)
{
if (count == 1)
{
yield return first.ToString();
}
//else if (count == 2)
//{
// yield return first.ToString();
// yield return last.ToString();
//}
else
{
yield return first.ToString() + "-" + last.ToString();
}
if (end) { yield break; }
first = en.Current;
count = 1;
}
else
{
++count;
}
last = en.Current;
}
}
}
Benchmarks
Lets measure how (in)efficient the linq actually is here on 10M array:
simple loop: 328MB, 1.2sec
my linq: 790MB, 2.7sec
Fredous linq: 1100MB, 7days (estimated)
the code:
int size = 10000000;
int[] arr = new int[size];
Random rnd = new Random(1);
arr[0] = 0;
for(int i = 1; i < size; ++i)
{
if (rnd.Next(100) < 25)
{
arr[i] = arr[i - 1] + 2;
}
else
{
arr[i] = arr[i - 1] + 1;
}
}
System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
st.Start();
var res = Group(arr).ToList();
st.Stop();
MessageBox.Show(st.ElapsedMilliseconds.ToString());
MessageBox.Show(res.Sum(s => s.Length).ToString());// to be sure the work is done
I was asked to make a Dice program with two arrays (one for each dice) and add the two results, e.g.: 2 (dice 1) + 6 (dice 2) = 8.
The program must roll the dices 100 times and show the sum each time.
I could do it so far, but the program also must show which sum is the most frequent, and which sum is the least frequent.
Like this: sum = [2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6]. Most common: 2; Least common: 5.
How can I do it?
This is how my code looks like:
static void Main(string[] args)
{
Random gerador = new Random();
int[] soma = new int[100];
int rolagem = 0;
for(int i = 0; i < soma.Length; i++)
{
rolagem = 0;
rolagem += gerador.Next(6) + 1;
rolagem += gerador.Next(6) + 1;
soma[i] = rolagem;
}
var mais = soma.GroupBy(item => item).OrderByDescending(g => g.Count()).Select(g => g.Key).First();
//NEED TO FIND OUT LEAST COMMON SUM
for (int j = 1; j < soma.Length; j++)
{
Console.Write("{0} ", soma[j]);
}
Console.WriteLine("Soma mais frequente: {0}, Soma menos frequente: {1}", mais, menos);
Console.ReadKey();
}
You're almost there, you can find the least common one similarly:
var array = new[] { 1, 1, 1, 1, 4, 2, 2, 3, 3, 3, 5, 5 };
var result = array.GroupBy(i => i).OrderBy(g => g.Count()).Select(g => g.Key).ToList();
var mostCommon = result.Last();
var leastCommon = result.First();
If you have code that rolls the dice 100 times, you are pretty close. All you need to do is frequency counters.
A roll of a pair of dice yields a number between 2 and 12, inclusive. Make an int count[13] array before entering the loop.
In the loop each time you have two numbers, say, d1 and d2, increment the count as follows:
count[d1+d2]++;
Once the loop is over, find the highest and the lowest numbers in the array between indexes 2 and 12, inclusive. The index of the highest number will be the number with the highest roll count; the index of the lowest number will be the number with the lowest roll count.
Tuple<int, int> least = new Tuple<int, int>(-1, -1), most = new Tuple<int, int>(-1, -1);
List<int> arr = new List<int> { 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6 };
var grp = arr.GroupBy(x => x).Select(x=>x).ToList();
foreach (var item in grp)
{
if (least.Item2 == -1 || least.Item2>item.Count())
{
var x = new Tuple<int, int>(item.Key, item.Count());
least = x;
}
if (most.Item2 == -1 || most.Item2 < item.Count())
{
var x = new Tuple<int, int>(item.Key, item.Count());
most = x;
}
}
Console.WriteLine("Least : "+least.Item1+" repeated " + least.Item2+"times");
Console.WriteLine("Most : "+most.Item1 + " repeated " + most.Item2 + "times");
Or as m1kael suggested,
Tuple<int, int> least = new Tuple<int, int>(-1, -1), most = new Tuple<int, int>(-1, -1);
List<int> arr = new List<int> { 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6 };
var grp = arr.GroupBy(x => x).OrderBy(x=>x.Count()).Select(x => x.Key).ToList();
Console.WriteLine("Least : "+ grp.First());
Console.WriteLine("Most : "+ grp.Last());
There is a small chance for more than one most or least common:
var a = Enumerable.Repeat(new Random(), 100).Select(r => r.Next(6) + r.Next(6) + 2);
var groups = a.GroupBy(i => i).GroupBy(g => g.Count(), g => g.Key).OrderBy(g => g.Key).ToList();
var mostCommon = string.Join(", ", groups.Last());
var leastCommon = string.Join(", ", groups[0]);
Here's what I mean. Suppose S = {1, 4} and N = 5. The ordered arrangements of elements in the set S would be like
{1}, {4}, {1,1}, {1,4}, {4,1}, {4,4}, {1,1,1}, ....
and the ones that sum up to N are
{1,4}, {4, 1}, {1,1,1,1,1}
I want an algorithm that finds those efficiently.
My "brute force" way would be like
static IEnumerable<IEnumerable<int>> OrderedArrangements(IEnumerable<int> nums, int k)
{
var singles = nums.Select(i => new int[] {i} );
var cumulative = singles;
for(int j = 2; j <= k; ++j)
{
var last = cumulative.Where(list => list.Count() == (j - 1));
var next = from x in singles
from y in last
select x.Concat(y);
cumulative = cumulative.Concat(next);
}
return cumulative;
}
and then
int sumToN = OrderedArrangements(new int[] {1, 4}, N)
.Where(x => x.Sum() == N);
but I'm wondering if there's an obvious and more efficient way to do this.
Just in case the above answer isn't clear enough, you could try straight forward recursion e.g.
...
/ \
(1) (4)
/ \ / \
(1)(4) (1)(4)
static void f(int sum, int n, String str, int[] arr){
if (n == sum){
Console.WriteLine(str);
return;
}
if (n > sum) return;
for (int i = 0; i < arr.Length; i++){
f(sum, n + arr[i], str + arr[i].ToString(), arr);
}
}
static void Main(string[] args){
int[] arr = { 1, 4 };
f(5, 0, "", arr);
}
Where sum is N in your question, n is initialized to 0, str is initialized to "" and arr is S in your question.
output:
11111
14
41
This works for me:
static IEnumerable<IEnumerable<int>> OrderedArrangements(IEnumerable<int> nums, int k)
{
return
k <= 0
? new [] { Enumerable.Empty<int>() }
: nums
.SelectMany(
n => OrderedArrangements(nums, k - n),
(n, ns) => new [] { n }.Concat(ns))
.Where(ns => ns.Sum() == k);
}
The result of OrderedArrangements(new [] { 1, 4 }, 5) is:
I ran this performance testing code:
Func<Func<IEnumerable<IEnumerable<int>>>, double> measure = f =>
{
var sw = Stopwatch.StartNew();
var result = f();
sw.Stop();
return sw.Elapsed.TotalMilliseconds;
};
var n = 200;
var a = 0.0;
var b = 0.0;
for (var i = 0; i < n; i++)
{
a += measure(() => OrderedArrangements_A(new [] { 1, 4, 9, 13 }, 50000));
b += measure(() => OrderedArrangements_B(new [] { 1, 4, 9, 13 }, 50000));
}
OrderedArrangements_A is the OP's code and OrderedArrangements_B is mine.
I got an average of 15.6ms for "A" and 0.004ms for "B". My code run about 3,895 times faster for this test.
I have an array of integers intx[]:
int[] intx = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
I need to find the first two digits which their sum is equal to 10.
Here's the code:
Output should like (4 and 6).
Output should like (3 and 7).
Output should like (2 and 8).
Output should like (1 and 9).
public string Test()
{
int[] intx = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int i, j = intx.Length-1;
string s = "";
for (i = 0; i < 4; i++)
{
if ((intx[i] + intx[j - 1]) == 10)
{
s = (intx[i].ToString() + " and " + intx[j - 1].ToString());
}
j--;
}
return s;
}
You could use LINQ:
int[] intx = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var twoDigitsSumEquals10 = intx
.SelectMany((i1, index) =>
intx.Skip(index + 1)
.Select(i2 => Tuple.Create(i1, i2)))
.Where(t => t.Item1 + t.Item2 == 10);
SelectMany builds a cartesian product between all ints in the array and all ints in the array with a greater index than the first(to prevent repetition).
Test:
foreach (var x in twoDigitsSumEquals10)
Console.WriteLine(string.Join(",", x));
Output:
(1, 9)
(2, 8)
(3, 7)
(4, 6)
or only the first with "and" between like (1 and 9):
var firstCombi = twoDigitsSumEquals10.First();
Console.Write("({0} and {1})", firstCombi.Item1, firstCombi.Item2);
Update: here's the same without LINQ:
List<Tuple<int, int>> pairs = new List<Tuple<int, int>>();
for (int i = 0; i < intx.Length - 1; i++)
{
for (int ii = i + 1; ii < intx.Length; ii++)
{
if(i + ii == 10)
pairs.Add(Tuple.Create(i, ii));
}
}
You don't do anything with s you just re assign it. Try adding the results to a list and return the list
public List<string> Test()
{
int[] intx = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int j = intx.Length-1;
List<string> result = new List<string>();
for (int i = 0; i < 4; i++)
{
if ((intx[i] + intx[j - 1]) == 10)
{
result.Add(intx[i].ToString() + " and " + intx[j--].ToString());
}
}
return result;
}
foreach(string s in Test())
Console.WriteLine(s);
To just return the first, then exit the loop early
public string Test()
{
int[] intx = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int j = intx.Length-1;
for (int i = 0; i < 4; i++)
{
if ((intx[i] + intx[j - 1]) == 10)
{
return (intx[i].ToString() + " and " + intx[j--].ToString());
}
}
return "";
}