How to generate dynamic for loop - c#

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

Related

How can sort by odd,even row?

I hava jagged Array
I want sort first,third row ascending order and second,fourth row descending order
public class JaggedArrayTest {
public static void Main() {
int[][] arr = new int[4][] {
new int[] {
11,
78,
56,
21
},
new int[] {
2,
7,
5,
6
},
new int[] {
8,
3,
9,
12
},
new int[] {
1,
10,
19,
17
}
};
// Traverse array elements
for (int i = 0; i < arr.Length; i++) {
for (int j = 0; j < arr[i].Length; j++) {
System.Console.Write(arr[i][j] + " ");
}
System.Console.WriteLine();
}
}
}
I want output like this
11, 21, 56, 78 
7, 6, 5,2
3, 8,9,12
19,17,10,1
Algo:-
Loop through each row.
Use Array.Sort() to sort each row
for(int row = 0; row < arr.Length; row++)
{
Array.Sort(arr[row]);
}
Although a little "allocatey", this can be done with linq and the remainder operator (to test for odd or even) fairly easily
The remainder operator ``% computes the remainder after dividing its
left-hand operand by its right-hand operand.
var results = arr.Select((values, i)
=> (i % 2 == 0 ? values.OrderBy(x => x) : values.OrderByDescending(x => x)).ToArray())
.ToArray();
foreach (var values in results)
Console.WriteLine(string.Join(", ",values));
Or an in situ, less "allocatey", and more idiomatic approach
for (var i = 0; i < arr.Length; i++)
{
Array.Sort(arr[i]);
if(i % 2 != 0)
Array.Reverse(arr[i]);
}
Output
11, 21, 56, 78
7, 6, 5, 2
3, 8, 9, 12
19, 17, 10, 1

Get possible ranges of int collection [duplicate]

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

C# - How to find the most common and the least common integers in an array?

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]);

Splitting a list of items evenly between x number of smaller lists

I'm asking this question again, since the last time I asked it, it was falsely marked as duplicated. I am going to include some more information this time, that might make it easier to understand my need (it may very well have been my own fault for not defining the question properly).
I'm trying to split a list of a generic type into 4 lists. For simplicity and understanding, I will use a list of integers in this example, but that shouldn't make a difference.
I have done a lot of searching, found multiple answers like "Split List into Sublists with LINQ", using batch methods to split, I have tried MoreLinq's Batch methods and so on. Those suggestions work fine for what they should, but they do not work the way I need them to.
If I have a list containing the following elements (integers ranging 1-25):
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
Then what I need to do is make 4 lists with a variable number of elements in them, where the elements increment in the same list, instead of jumping to the next list with the next element.
[ 1, 2, 3, 4, 5, 6, 7]
[ 8, 9, 10, 11, 12, 13, 14]
[15, 16, 17, 18, 19, 20, 21]
[20, 21, 22, 23, 24, 25]
When using the solutions in either of the questions linked, with 4 "parts" as the parameter, I get lists like this (this is the example where the element jumps to the next list instead of just the next element of the list):
[1, 5, 9, 13, 17, 21, 25],
[2, 6, 10, 14, 18, 22, 26],
[3, 7, 11, 15, 19, 23, 27],
[4, 8, 12, 16, 20, 24]
or this (does the same as MoreLinq's Batch method)
[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16],
[17, 18, 19, 20],
[21, 22, 23, 24],
[25, 26, 27],
So the first solution splits the list into 4 lists, but puts the elements in the wrong order. The second solution splits the lists in the right order, but not in the right length. In the last solution, he gets X amount of lists with 4 elements in each, where I need to have 4 lists with X elements in each.
You can use following extension method to split list on required number of sub-lists, and include additional items in first sub-list:
public static IEnumerable<List<T>> Split<T>(this List<T> source, int count)
{
int rangeSize = source.Count / count;
int firstRangeSize = rangeSize + source.Count % count;
int index = 0;
yield return source.GetRange(index, firstRangeSize);
index += firstRangeSize;
while (index < source.Count)
{
yield return source.GetRange(index, rangeSize);
index += rangeSize;
}
}
With given input
var list = Enumerable.Range(1, 25).ToList();
var result = list.Split(4);
Result is
[
[ 1, 2, 3, 4, 5, 6, 7 ],
[ 8, 9, 10, 11, 12, 13 ],
[ 14, 15, 16, 17, 18, 19 ],
[ 20, 21, 22, 23, 24, 25 ]
]
UPDATE: This solution adds additional item to each range
public static IEnumerable<List<T>> Split<T>(this List<T> source, int count)
{
int rangeSize = source.Count / count;
int additionalItems = source.Count % count;
int index = 0;
while (index < source.Count)
{
int currentRangeSize = rangeSize + ((additionalItems > 0) ? 1 : 0);
yield return source.GetRange(index, currentRangeSize);
index += currentRangeSize;
additionalItems--;
}
}
Here is another solution based on IEnumerable<T>. It has the following characteristics:
Always yields batchCount items, if the source enumerable is smaller than the batch size, it will yield empty lists.
Favors larger lists at the front (e.g. when the batchCount is 2 and the size is 3, the length of the results will be [2,1].
Iterates multiple times of the IEnumerable. This means AsEnumerable should be called somewhere if something like an Entity Framework query is executed here.
The first example is optimized for List<T>
public static class BatchOperations
{
public static IEnumerable<List<T>> Batch<T>(this List<T> items, int batchCount)
{
int totalSize = items.Count;
int remain = totalSize % batchCount;
int skip = 0;
for (int i = 0; i < batchCount; i++)
{
int size = totalSize / batchCount + (i <= remain ? 1 : 0);
if (skip + size > items.Count) yield return new List<T>(0);
else yield return items.GetRange(skip, size);
skip += size;
}
}
public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> items, int batchCount)
{
int totalSize = items.Count();
int remain = totalSize%batchCount;
int skip = 0;
for (int i = 0; i < batchCount; i++)
{
int size = totalSize/batchCount + (i <= remain ? 1 : 0);
yield return items.Skip(skip).Take(size);
skip += size;
}
}
}
Sergey's answer is clearly the best for this, but for completeness here's a solution you could use if you did not want to make copies of the sublists for some reason (perhaps because you just had IEnumerable<T> as input):
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
public static class EnumerableExt
{
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> input, int blockCount, int count)
{
int blockSize = count/blockCount;
int currentBlockSize = blockSize + count%blockSize;
var enumerator = input.GetEnumerator();
while (enumerator.MoveNext())
{
yield return nextPartition(enumerator, currentBlockSize);
currentBlockSize = blockSize;
}
}
private static IEnumerable<T> nextPartition<T>(IEnumerator<T> enumerator, int blockSize)
{
do
{
yield return enumerator.Current;
}
while (--blockSize > 0 && enumerator.MoveNext());
}
}
class Program
{
private void run()
{
var list = Enumerable.Range(1, 25).ToList();
var sublists = list.Partition(4, list.Count);
foreach (var sublist in sublists)
Console.WriteLine(string.Join(" ", sublist.Select(element => element.ToString())));
}
static void Main()
{
new Program().run();
}
}
}
I guess this would run much more slowly than using Lists, but it would use much less memory.
const int groupSize = 4;
var items = new []{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25};
var currentGroupIndex=-1;
var step1 = items.Select(a =>{
if (++currentGroupIndex >= groupSize)
currentGroupIndex = 0;
return new {Group = currentGroupIndex, Value = a};
}).ToArray();
var step2 = step1.GroupBy(a => a.Group).Select(a => a.ToArray()).ToArray();
var group1 = step2[0].Select(a => a.Value).ToArray();
var group2 = step2[1].Select(a => a.Value).ToArray();
var group3 = step2[2].Select(a => a.Value).ToArray();
var group4 = step2[3].Select(a => a.Value).ToArray();
What this does is it first introduces an counter (currentGroupIndex) which starts at zero and will be incremented for each element in the list. The index gets reset to zero when the group size has reached.
the variable step1 now contains items continaing a Group and a Value property.
The Group value is then used in the GroupBy statement.
Take & Skip could be very helpful here i think but personally i like using Func to make these choices, makes the method more flexible.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Splitter
{
class Program
{
static void Main(string[] args)
{
List<int> numbers = Enumerable.Range(1, 25).ToList();
int groupCount = 4;
var lists = numbers.Groupem(groupCount, (e, i) =>
{
// In what group do i wanna have this element.
int divider = numbers.Count / groupCount;
int overflow = numbers.Count % divider;
int index = (i - overflow) / divider;
return index < 0 ? 0 : index;
});
Console.WriteLine("numbers: {0}", numbers.ShowContent());
Console.WriteLine("Parts");
foreach (IEnumerable<int> list in lists)
{
Console.WriteLine("{0}", list.ShowContent());
}
}
}
public static class EnumerableExtensions
{
private static List<T>[] CreateGroups<T>(int size)
{
List<T>[] groups = new List<T>[size];
for (int i = 0; i < groups.Length; i++)
{
groups[i] = new List<T>();
}
return groups;
}
public static void Each<T>(this IEnumerable<T> source, Action<T, int> action)
{
var i = 0;
foreach (var e in source) action(e, i++);
}
public static IEnumerable<IEnumerable<T>> Groupem<T>(this IEnumerable<T> source, int groupCount, Func<T, int, int> groupPicker, bool failOnOutOfBounds = true)
{
if (groupCount <= 0) throw new ArgumentOutOfRangeException("groupCount", "groupCount must be a integer greater than zero.");
List<T>[] groups = CreateGroups<T>(groupCount);
source.Each((element, index) =>
{
int groupIndex = groupPicker(element, index);
if (groupIndex < 0 || groupIndex >= groups.Length)
{
// When allowing some elements to fall out, set failOnOutOfBounds to false
if (failOnOutOfBounds)
{
throw new Exception("Some better exception than this");
}
}
else
{
groups[groupIndex].Add(element);
}
});
return groups;
}
public static string ShowContent<T>(this IEnumerable<T> list)
{
return "[" + string.Join(", ", list) + "]";
}
}
}
How about this, includes parameter checking, works with an emtpy set.
Completes in two passes, should be fast, I haven't tested.
public static IList<Ilist<T>> Segment<T>(
this IEnumerable<T> source,
int segments)
{
if (segments < 1)
{
throw new ArgumentOutOfRangeException("segments");
}
var list = source.ToList();
var result = new IList<T>[segments];
// In case the source is empty.
if (!list.Any())
{
for (var i = 0; i < segments; i++)
{
result[i] = new T[0];
}
return result;
}
int remainder;
var segmentSize = Math.DivRem(list.Count, segments, out remainder);
var postion = 0;
var segment = 0;
while (segment < segments)
{
var count = segmentSize;
if (remainder > 0)
{
remainder--;
count++;
}
result[segment] = list.GetRange(position, count);
segment++;
position += count;
}
return result;
}
Here is an optimized and lightweight O(N) extension method solution
public static void Bifurcate<T>(this IEnumerable<T> _list, int amountOfListsOutputted, IList<IList<T>> outLists)
{
var list = _list;
var index = 0;
outLists = new List<IList<T>>(amountOfListsOutputted);
for (int i = 0; i < amountOfListsOutputted; i++)
{
outLists.Add(new List<T>());
}
foreach (var item in list)
{
outLists[index % amountOfListsOutputted].Add(item);
++index;
}
}
Simply use it like this:
public static void Main()
{
var list = new List<int>(1000);
//Split into 2
list.Bifurcate(2, out var twoLists);
var splitOne = twoLists[0];
var splitTwo = twoLists[1];
// splitOne.Count == 500
// splitTwo.Count == 500
//Split into 3
list.Bifurcate(3, out var threeLists);
var _splitOne = twoLists[0];
var _splitTwo = twoLists[1];
var _splitThree = twoLists[2];
// _splitOne.Count == 334
// _splitTwo.Count = 333
// _splitThree.Count == 333
}

Find the first two digits which their sum is equal to 10

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

Categories

Resources