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 "";
}
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
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.
Let's say I have a list of predefined numbers, and a list of predefined max limits.
When a user picks a limit, I need to randomly pick a certain amount of numbers from the first list, up until their totals match (As close to, but never over) the user selected total.
What I've tried so far:
void Main()
{
List<int> num = new List<int>(){ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,17, 18, 19, 20 };
int maxNum = 17;
List<int> curNum = new List<int>();
int curTotal = 0;
foreach(int sel in num.Where(x => x < maxNum)){
curTotal += sel;
if(curTotal <= maxNum){
curNum.Add(sel);
}
}
}
There needs to be x amount of numbers picked. In this case, 5 numbers picked, +- 20 numbers to be randomly picked from, and 1 max values.
So the end list should look like this:
1, 2, 3, 4, 7 (17)
1, 2, 3, 5, 6 (17)
1, 2, 3, 4, 6 (16) <- This will be fine if there isn't a solution to the max value.
Building upon #AlexiLevenkov's answer:
class Program
{
static void Main(string[] args)
{
int limit = 17;
int listSize = 5;
List<int> a = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
a.Shuffle();
List<int> genList = new List<int>();
int stoppedCount = 0;
for (int i = 0; i < a.Count(); i++)
{
if (i < listSize)
{
genList.Add(a[i]);
stoppedCount = i;
}
else
{
break;
}
}
while (genList.Sum() > limit)
{
genList.Remove(genList.Max());
stoppedCount++;
genList.Add(a[stoppedCount]);
}
}
}
static class ThisClass
{
public static void Shuffle<T>(this IList<T> list)
{
Random rng = new Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
I think shuffle + "take while sum < limit" may be what you are looking for.
Something like following:
var shuffledList = num.ToList();
shuffledList.Shuffle();
var sum = 0;
var count = 0;
while (shuffledList[count] + sum < max)
{
sum += shuffledList[count++];
}
return shuffledList.Take(count);
There are 5 cascading combo boxes in a page which are dynamically created.
I have to do something when the desired sum is achieved. This is my code which generates some output; I want to generate all the for loops and even the all 'cmb' arrays dynamically. How can I achieve it?
private int[] cmb1 = { 0, 2, 4, 6, 8, 12, 16, 20 };
private int[] cmb2 = { 0, 2, 4, 6, 8, 12, 16, 20 };
private int[] cmb3 = { 0, 2, 4, 6, 8, 12, 16, 20 };
private int[] cmb4 = { 0, 2, 4, 6, 8, 12, 16, 20 };
private int[] cmb5 = { 0, 2, 4, 6, 8, 12, 16, 20 };
int count = 0;
for (int i = 0; i < cmb1.Length; i++)
{
for (int j = 0; j < cmb2.Length; j++)
{
for (int k = 0; k < cmb3.Length; k++)
{
for (int l = 0; l < cmb4.Length; l++)
{
for (int m = 0; m < cmb5.Length; m++)
{
if (cmb1[i] + cmb2[j] + cmb3[k] + cmb4[l] + cmb5[m] <= 20 && (i + j + k + l + m) != 0)
{
Console.WriteLine(count + " _ " + i + " " + j + " " + k + " " + l + " " + m);
count = count + 1;
}
}
}
}
}
}
What you're looking to do can be considered the Cartesian Product of an unknown (at compile time) number of sequences.
Eric Lippert wrote a blog post about how to create such a solution in C#. The code he ends up generating is:
public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }));
}
Using this we can now do:
List<int[]> cmbs = new List<int[]>();
cmbs.Add(new int[] { 0, 2, 4, 6, 8, 12, 16, 20 });
cmbs.Add(new int[] { 0, 2, 4, 6, 8, 12, 16, 20 });
cmbs.Add(new int[] { 0, 2, 4, 6, 8, 12, 16, 20 });
var query = cmbs.CartesianProduct()
.Where(combo => combo.Sum() <= 20 && combo.Sum() > 0);
int count = 0;
foreach (var combo in query)
{
Console.Write((count++) + " _ ");
Console.WriteLine(string.Join(" ", combo));
}
I'll direct you to Eric Lippert's excellent article on implementing a Cartesian product in Linq, which he wrote as a generic extension method:
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
// base case:
IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
foreach(var sequence in sequences)
{
var s = sequence; // don't close over the loop variable
// recursive case: use SelectMany to build the new product out of the old one
result =
from seq in result
from item in s
select seq.Concat(new[] {item});
}
return result;
}
So in your code you would call it like this:
private List<int[]> cmbs = new List<int[]>();
...
// build cmbs list
cmbs.Add(cmb1);
cmbs.Add(cmb2);
cmbs.Add(cmb3);
cmbs.Add(cmb4);
cmbs.Add(cmb5);
// loop through cmbs
var count = 0;
foreach(var result in cmbs.CartesianProduct().Skip(1)) // Skip the first result
{
if (result.Sum() <= 20)
{
Console.WriteLine(count + "_" + String.Join(" ", result));
count = count + 1;
}
}