Array.IndexOf vs. value of given index issue - c#

I'm trying to loop through a given array and find how many duplicate values I have inside it. It works by going through a nested loop checking all elements of the array against each other and making sure it doesn't rise the counter if it's on the same index. But the problem is, it never counts up!
Now it's either I don't understand the concept of valueOf vs indexOf or I'm just completely lost.
int[] myArr = new int[] { 10, 5, 5 };
int counter = 0;
for (int i = 0; i < myArr.Length; i++)
{
for (int j = 0; j < myArr.Length; j++)
{
if (Array.IndexOf(myArr, myArr[i]) == Array.IndexOf(myArr, myArr[j]))
{
continue;
}
else if (myArr[i] == myArr[j])
{
counter++;
}
}
}
Console.WriteLine("There are {0} repeating values in the array.", counter);
// Output: There are 0 repeating values in the array.

Array.IndexOf searches for the first occurrence of the value in the array.
It looks like in your example you are trying to use it to make sure you're not comparing the same position in the array. In which case you could just replace that condition with if(i == j)

Going along with the other answers/comments stating the Array.IndexOf is not the correct approach to this problem, and not exactly sure if you're allowed to use LINQ, but that is by far a better approach, especially using the GroupBy method.
I have created a dotnetfiddle for you to show what I am doing.
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
int[] myArr = new int[] { 10, 5, 5, 3, 3, 3 };
// int counter = 0; - now this is no longer needed
var numbersThatAreDuplicates = myArr.GroupBy(x => x).Where(x => x.Count() > 1).Select(x => new { number = x.Key, countOfNumber = x.Count()}).ToList();
Console.WriteLine("There are {0} repeating values in the array.", numbersThatAreDuplicates.Count);
foreach (var item in numbersThatAreDuplicates)
{
Console.WriteLine(item.number + " repeats itself " + item.countOfNumber + " times.");
}
}
}
// Output
// There are 2 repeating values in the array.
// 5 repeats itself 2 times.
// 3 repeats itself 3 times.
As you can see, via the GroupBy method, you can find out how many numbers are repeating, as well as what the actual numbers are along with the number of occurrences that the actual number repeats itself in 1 line of code. Much cleaner, and efficient than using nesting for loops, but again I am not sure of what your limitations are.
I hope this helps.

You don't need to use the Array.IndexOf() function.
for example:
int[] myArr = new int[] { 10, 5, 5, 5};
int counter = 0;
List<int> dups = new List<int>();
for (int i = 0; i < myArr.Length; i++)
{
for (int j = 0; j < myArr.Length; j++)
{
if (i != j && myArr[i] == myArr[j] && !dups.Contains(i))
{
dups.Add(j);
counter++;
}
}
}
Console.WriteLine("There are {0} repeating values in the array.", counter);
// Output: There are 2 repeating values in the array.

Related

My code does not check the indexes of all of the arrays (lottery program)

I am making a lottery program, it's basic and only view-able via console at the moment.
The program executes the following:
User enters 6 numbers ranging from 1 - 46.
Program generates 6 random numbers with the same range.
Program compares indexes to see which numbers the user managed to match with the program.
Program displays the same numbers which the user got right.
But, currently, there is a bug in my code and I am not sure how to proceed.
For example, my inputs are: 1 , 2 , 3 , 4 , 5 , 6
The program generated 6 numbers and I've managed to hit number 2 and 6.
But, the program only displayed number 2.
This means that my code is not comparing each and every index, and I am not sure why.
The user array is lucky, and the program generated array is numbers.
Console.WriteLine("The winning numbers are: , " );
int[] winning = new int[6];
int w = 0;
var x = 0;
var j = 0;
Console.WriteLine("The winning numbers are: , " );
int[] winning = new int[6];
int w = 0;
var x = 0;
var j = 0;
while (x< 6)
{
if (lucky[j] == numbers[x])
{
winning[w] = numbers[x];
Console.WriteLine(winning[w]);
w++;
}
j++;
if (j == 5)
{
x++;
j = 0;
}
}
There is no need to do all that looping these days. LINQ's Intersect function makes it a single function call:
var Matches = lucky.Intersect(numbers);
will return all matching numbers from the two lists in Matches.
A looping equivalent might look like this (writing off the top of my head):
List<int> winning = new List<int>();
for(int i=0; i<numbers.Length; i++)
{
if(numbers.Contains(lucky[i])
winning.Add(lucky[i]);
}
To display it on console, use a simple loop:
for(int i=0; i<winning.Length; i++)
{
Console.WriteLine(winning[i]);
}
Since you run over an array, the standard procedure would be to use a for loop.
Here are three solutions that solve the problem.
Each one is complete and can be tested on https://dotnetfiddle.net/
Linq: Use the Intersects method to find the common items between two IEnumerables.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// at this point unique numbers have been generated and inputted
int[] numbers = { 1, 2, 3, 4, 5, 6 };
int[] guesses = { 2, 6, 7, 8, 9, 10 };
List<int> matches = new List<int>(numbers.Intersect(guesses));
foreach (int n in matches)
{
Console.WriteLine("Hit: " + n.ToString());
}
}
}
Using a single for loop and checking with the Contains method (Array implements the IList interface) if the other array contains the number at the current index. You could also use a foreach loop, since you don't care about the indexes.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// at this point unique numbers have been generated and inputted
int[] numbers = { 1, 2, 3, 4, 5, 6 };
int[] guesses = { 2, 6, 7, 8, 9, 10 };
List<int> matches = new List<int>();
for (int i = 0; i < guesses.Length; i++)
{
if (numbers.Contains(guesses[i]))
{
Console.WriteLine("Hit: " + guesses[i].ToString());
matches.Add(guesses[i]);
}
}
}
}
Of you could use a nested for loops, one for each array, to check each number from one array against every number of the other one.
Again you could use foreach loops.
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
// at this point unique numbers have been generated and inputted
int[] numbers = { 1, 2, 3, 4, 5, 6 };
int[] guesses = { 2, 6, 7, 8, 9, 10 };
List<int> matches = new List<int>();
for (int i = 0; i < guesses.Length; i++)
{
for (int j = 0; j < numbers.Length; j++)
{
if (guesses[i] == numbers[j])
{
Console.WriteLine("Hit: " + guesses[i].ToString());
matches.Add(guesses[i]);
break; // optional, we found the number and can leave the loop. Not optional if your lottery allows numbers to happen more than once.
}
}
}
}
}
As for the question why your code isn't working:
You set j = 0 when j == 5 just after j++, meaning you set j to 0 after checking index 4. While I do not want to encourage such unorthodox styles you could fix it by comparing j == 6. Again, this approach makes your code unreadable, please use one of the other solutions.
using System;
public class Program
{
public static void Main()
{
// at this point unique numbers have been generated and inputted
int[] numbers = { 1, 2, 3, 4, 5, 6 };
int[] guesses = { 2, 6, 7, 8, 9, 10 };
int[] winning = new int[6];
int w = 0;
var x = 0;
var j = 0;
while (x < 6)
{
if (guesses[j] == numbers[x])
{
winning[w] = numbers[x];
Console.WriteLine(winning[w]);
w++;
}
j++;
if (j == 6)
{
x++;
j = 0;
}
}
}
}
I think what you are looking for is that finding common items from two arrays.
var ar1 = new int[] {1,2,3,4,5,6};
var ar2 = new int[] {2,3,4,6,7,8};
var common = ar1.Intersect(ar2);
In your case
var common = lucky.Intersect(numbers);
Using loops
// Array size is fixed here.
for (int i = 0; i < 6; i++) // OR i < lucky.Length (guessing numbers)
{
if (numbers.Contains(lucky[i]))
{
// NUMBERS DETECTED
}
}
The issue is with the checking of last index(5 in this case). It is never happening!
//say j = 4
lucky[4] == numbers[x] //false/true, whatever value of x is
You increment j
//j is now 5
if(j==5)
Yes and then you are resetting it to 0.
last index which is 5 in this case will never be checked in the next iteration
Solution-
if(j == 6)
I ended up building 2 methods that basically do what everyone here has told me.
Since I did not yet learn LinQ I couldn't understand , I didn't learn LIST as well so I couldn't use it as well.
My functions are like this:
First function: checks the indexes of a specified array
code:
static bool DoesExists(int[] a, int Value)
{
for (int i = 0; i < a.Length; i++)
{
if (Value == a[i])
{
return true;
}
}
return false;
}
second function checks how many repeated elements are in 2 arrays
code:
static int CountCorrect(int[] pc, int[] user)
{
int count = 0;
for (int i = 0; i < user.Length; i++)
{
if (DoesExists(pc, user[i]))
{
count++;
}
}
return count;
}
when using these 2 in conjunction , it solves my problem.
thanks to everyone for taking the time to give me good ideas.

Comparing c# array to itself

I'm trying to solve whats probably an easy task, but I'm extremely new to this and don't quite have my head around working with arrays in a complex fashion. I'm trying to figure out if two inputs each corresponding numbers sum to the same number (for example with 123 and 321, 1+3 2+2 and 1+3 all equal 4).
The code I have so far has broken down each input into arrays, and I can sum those arrays into a third array, but I cant figure out how to check it with itself. Should I even bother with the 3rd array, and just figure out how to check the sums of the array in a loop?
public static void Main()
{
Console.Write("\n\n"); //begin user input
Console.Write("Check whether each cooresponding digit in two intigers sum to the same number or not:\n");
Console.Write("-------------------------------------------");
Console.Write("\n\n");
Console.Write("Input 1st number then hit enter: ");
string int1 = (Console.ReadLine());//user input 1
Console.Write("Input 2nd number: ");
string int2 = (Console.ReadLine());//user input 2
int[] numbers = new int[int1.ToString().Length]; //changing user inputs to strings for array
int[] numbers2 = new int[int2.ToString().Length];
for (int i = 0; i < numbers.Length; i++)
{
numbers[i] = int.Parse(int1.Substring(i, 1));//populating arrays
numbers2[i] = int.Parse(int2.Substring(i, 1));
}
int[] numbers3 = new int[numbers.Length];
for (int i = 0; i < numbers.Length; i++)
{
numbers3[i] = (numbers[i] + numbers2[i]);
}
}
}
You can create the collections on the fly...
bool isEqual = Console.ReadLine()
.ToCharArray()
.Select(i => Convert.ToInt32(i.ToString()))
.Zip(Console.ReadLine()
.ToCharArray()
.Select(i => Convert.ToInt32(i.ToString())),
(i, j) => new
{
First = i,
Second = j,
Total = i + j
})
.GroupBy(x => x.Total)
.Count() == 1;
The output will equal true if all elements add up to the same value...
Test cases:
Should succeed
12345
54321
Should fail
12345
55432
To understand the above query, lets break it up into sections.
// Here I'm just converting a string to an IEnumerable<int>, a collection of integers basically
IEnumerable<int> ints1 = Console.ReadLine()
.ToCharArray()
.Select(i => Convert.ToInt32(i.ToString()));
IEnumerable<int> ints2 = Console.ReadLine()
.ToCharArray()
.Select(i => Convert.ToInt32(i.ToString()));
// Zip brings together two arrays and iterates through both at the same time.
// I used an anonymous object to store the original values as well as the calculated ones
var zippedArrays = ints1.Zip(ints2, (i, j) => new
{
First = i, // original value from ints1
Second = j, // original values from ints2
Total = i + j // calculated value ints1[x] + ints2[x]
});
// if the totals are [4,4,4], the method below will get rid of the duplicates.
// if the totals are [4,3,5], every element in that array would be returned
// if the totals are [4,4,5], only [4,5] would be returned.
var distinctByTotal = zippedArrays.GroupBy(x => x.Total);
// So what does this tell us? if the returned collection has a total count of 1 item,
// it means that every item in the collection must have had the same total sum
// So we can say that every element is equal if the response of our method == 1.
bool isEqual = distinctByTotal.Count() == 1;
You're 99% of the way there already. Just lose the third array and check each individual sum in your final loop.
bool isOK = numbers.Length = numbers2.Length && numbers.Length > 0;
if(isOK)
{
int expectedSum = numbers[0] + numbers2[0];
for (int i = 1; i < numbers.Length; i++)
{
var sum = (numbers[i] + numbers2[i]);
if(sum != expectedSum)
{
isOK = false;
break;
}
}
}
Console.WriteLine(isOk ? "Good job." : "You got some learning to do.");

C#, how to save frequency of elements from one array in another, two-dimensional array?

So here's my problematic code. When I try to pass an array with N arguments, let's say {2,1,2,2,5} in result I want to get two-dimensional secArray[element,frequency of the element]. The problem is I get more than that and in this particular case I get an array like this:
23
11
22
21
52
Console.WriteLine("Enter number of elements: ");
int n = int.Parse(Console.ReadLine());
int[] array = new int[n];
for (int i = 0; i < array.Length; i++)
{
Console.Write("Array[{0}]: ", i);
array[i] = int.Parse(Console.ReadLine());
}
//problematic code begins
int[,] secArray = new int[n,2];
for(int i = 0;i<n;i++)
{
for(int j = 0; j<n;j++)
{
if(array[i] == secArray[j,0])
{
secArray[j, 1] += 1;
}
else
{
secArray[i, 0] = array[i];
secArray[i, 1] = 1;
}
}
}
//problematic code ends
//printing - works good
Console.WriteLine("How many same elements?");
for (int row = 0; row < secArray.GetLength(0); row++)
{
for (int col = 0; col < secArray.GetLength(1); col++)
{
Console.Write(secArray[row, col]);
}
Console.WriteLine();
}
If anyone has a clue how to fix this I'll be really grateful. It frustrates me that I don't know where the actual problem lies.
The first problem concerns the very first statement.
int[,] secArray = new int[n,2];
You don't know how many unique elements you have in your array until you traverse it. You can't use n, because n is the total number of arguments, which can be greater than the number of unique elements.
Next, the nested for loops are very inefficient. Your algorithm traverses the array for every element in the array- so it will run in O(n^2) time.
Think: do you have to traverse the array more than once? Why not just use a hashtable (dictionary in C#) to keep track of counts as you traverse the array? A hashtable uses a very efficient lookup mechanism to tell you if you've already seen the element, and the value can be used to keep track of count.
Consider replacing your problematic code with the following, and understanding how it works.
Dictionary<int, int> elementCounts = new Dictionary<int, int>();
for(int i = 0; i < n; i++)
{
int element = array[i];
if (elementCounts.ContainsKey(element))
elementCounts[element]++;
else
elementCounts.Add(element, 1);
}
Console.WriteLine("How many same elements?");
foreach(KeyValuePair<int,int> count in elementCounts)
{
Console.WriteLine("Element: {0} Count: {1}", count.Key, count.Value);
}
Then, if you want to copy the results in the hashtable (Dictionary) to a two-dimensional array, you can do the following.
int numberOfUniqueElements = elementCounts.Count;
int[,] secArray = new int[numberOfUniqueElements, 2];
int j = 0;
foreach (KeyValuePair<int, int> count in elementCounts)
{
secArray[j, 0] = count.Key;
secArray[j, 1] = count.Value;
j++;
}
I would use Linq's GroupBy to do this
var array = new int[] { 2, 1, 2, 2, 5 };
var result = array.GroupBy(x => x).Select(x => new[] { x.Key, x.Count() }).ToArray();
Why don't you use a hash table. Let the number in the array be the hash entry key, and let the value of the hash entry be the count. Then just iterate through the array once. While iterating through the array check if hash entry exists if so add 1 to it, if not create it.
Something like
for(int i = 0; i<n;i++) {
if(hashTable.containsKey(array[i])) {
hashTable[array[i]]++];
} else {
hashTable.add(array[i],1);
}
}
Please note that this is quedocode and will require to lookup the methods and implement it correctly.

find number with no pair in array

I am having trouble with a small bit of code, which in a random size array, with random number pairs, except one which has no pair.
I need to find that number which has no pair.
arLength is the length of the array.
but i am having trouble actually matching the pairs, and finding the one which has no pair..
for (int i = 0; i <= arLength; i++)
{ // go through the array one by one..
var number = nArray[i];
// now search through the array for a match.
for (int e = 0; e <= arLength; e++)
{
if (e != i)
{
}
}
}
I have also tried this :
var findValue = nArray.Distinct();
I have searched around, but so far, i haven't been able to find a method for this.
This code is what generates the array, but this question isn't about this part of the code, only for clarity.
Random num = new Random();
int check = CheckIfOdd(num.Next(1, 1000000));
int counter = 1;
while (check <= 0)
{
if (check % 2 == 0)
{
check = CheckIfOdd(num.Next(1, 1000000)); ;
}
counter++;
}
int[] nArray = new int[check];
int arLength = 0;
//generate arrays with pairs of numbers, and one number which does not pair.
for (int i = 0; i < check; i++)
{
arLength = nArray.Length;
if (arLength == i + 1)
{
nArray[i] = i + 1;
}
else
{
nArray[i] = i;
nArray[i + 1] = i;
}
i++;
}
You can do it using the bitwise operator ^, and the complexity is O(n).
Theory
operator ^ aka xor has the following table:
So suppose you have only one number without pair, all the pairs will get simplified because they are the same.
var element = nArray[0];
for(int i = 1; i < arLength; i++)
{
element = element ^ nArray[i];
}
at the end, the variable element will be that number without pair.
Distict will give you back the array with distinct values. it will not find the value you need.
You can GroupBy and choose the values with Count modulo 2 equals 1.
var noPairs = nArray.GroupBy(i => i)
.Where(g => g.Count() % 2 == 1)
.Select(g=> g.Key);
You can use a dictionary to store the number of occurrences of each value in the array. To find the value without pairs, look for a (single) number of occurrences smaller than 2.
using System.Linq;
int[] data = new[] {1, 2, 3, 4, 5, 3, 2, 4, 1};
// key is the number, value is its count
var numberCounts = new Dictionary<int, int>();
foreach (var number in data) {
if (numberCounts.ContainsKey(number)) {
numberCounts[number]++;
}
else {
numberCounts.Add(number, 1);
}
}
var noPair = numberCounts.Single(kvp => kvp.Value < 2);
Console.WriteLine(noPair.Key);
Time complexity is O(n) because you traverse the array only a single time and then traverse the dictionary a single time. The same dictionary can also be used to find triplets etc.
.NET Fiddle
An easy and fast way to do this is with a Frequency Table. Keep a dictionary with as key your number and as value the number of times you found it. This way you only have to run through your array once.
Your example should work too with some changes. It will be a lot slower if you have a big array.
for (int i = 0; i <= arLength; i++)
{
bool hasMatch = false;
for (int e = 0; e <= arLength; e++)
{
if (nArray[e] == nArray[i])//Compare the element, not the index.
{
hasMatch = true;
}
}
//if hasMatch == false, you found your item.
}
All you have to do is to Xor all the numbers:
int result = nArray.Aggregate((s, a) => s ^ a);
all items which has pair will cancel out: a ^ a == 0 and you'll have the distinc item: 0 ^ 0 ^ ...^ 0 ^ distinct ^ 0 ^ ... ^0 == distinct
Because you mentioned you like short and simple in a comment, how about getting rid of most of your other code as well?
var total = new Random().Next(500000) * 2 + 1;
var myArray = new int[total];
for (var i = 1; i < total; i+=2)
{
myArray[i] = i;
myArray[i -1] = i;
}
myArray[total - 1] = total;
Then indeed use Linq to get what you are looking for. Here is a slight variation, returning the key of the item in your array:
var key = myArray.GroupBy(t => t).FirstOrDefault(g=>g.Count()==1)?.Key;

Sum of Array's Subsets

Im looking for some help with finding subsets of array.
int[] array = { 1,2,3,5,8,10,15,23};
I have to find all subsets of an array. If sum of the subsets elements equal to any number in array then my counter increment. For example: 1+2=3, 2+3=5, 5+8+10=23, 1+2+5=8, 2+3+8+10=23
public static void Main(string[] args)
{
int[] array = { 1, 2, 3, 5, 8, 10, 15, 23 };
int arrayLength = array.Count();
int sum = 0;
int subsetCount = 0;
for (int i = 0; i < arrayLength; i++)
{
for (int j = i + 1; j < arrayLength; j++)
{
sum = array[i] + array[j];
for (int m = j + 1; m < arrayLength; m++)
{
for (int k = 0; k < arrayLength; k++)
{
if (array[k] == sum)
{
subsetCount++;
}
}
sum = array[i] + array[j] + array[m];
}
}
}
Console.WriteLine(subsetCount);
Console.ReadLine();
}
I'm ok with 2-elements and 3-elements of subsets. But 4 and above I can't figured out how to solve it?
Any help would be greatly appreciated
You only need two loops to find the sum of all subsets. The outer loop is the starting point of subsets, and the inner loop is calculating the sums of all subsets from that starting point.
With the first index as starting points the subsets are 1+2, 1+2+3, 1+2+3+5 and so on. As you are only interested in the sum of the subsets you can just add one item after the other to get the sum of the subsets.
Then for each sum loop through the items to check for a match:
int[] array = { 1, 2, 3, 5, 8, 10, 15, 23 };
int subsetCount = 0;
for (int i = 0; i < array.Length; i++) {
int sum = array[i];
for (int j = i + 1; j < array.Length; j++) {
sum += array[j];
for (int k = 0; k < array.Length; k++) {
if (array[k] == sum) {
subsetCount++;
}
}
}
}
Console.WriteLine(subsetCount);
Edit:
I assumed that you meant continuous subsets, but from your examples it seems that you also want non-continuous subsets.
Lets's start with the correct solution:
23 = 15+8, 15+5+3, 15+5+2+1, 10+8+5, 10+8+3+2
15 = 10+5, 10+3+2, 8+5+2
10 = 8+2, 5+3+2
8 = 5+3, 5+2+1
5 = 3+2
3 = 2+1
That gives us 14 different subsets that sums up to an item in the set.
You can count the subsets recursively, only keeping track of the sum and number of items in subsets. You don't need the actual subsets, only to know the sum and that there are at least two items in the subset.
The subsets in a set is the first item combined with all subsets in the rest of the set, plus the subsets in the rest of the set. For example the subsets s() of [1,2,3] is 1,s([2,3]) and s([2,3]).
This gives you:
public static int CountSubsets(int[] arr, int start, int len, int sum) {
int cnt = 0;
if (start < arr.Length) {
if (len >= 1 && arr.Contains(sum + arr[start])) cnt++;
cnt += CountSubsets(arr, start + 1, len + 1, sum + arr[start]);
cnt += CountSubsets(arr, start + 1, len, sum);
}
return cnt;
}
And calling it:
int[] set = { 1, 2, 3, 5, 8, 10, 15, 23 };
Console.WriteLine(CountSubsets(set, 0, 0, 0));
Output:
14
This seems a lot like homework to me. So I will answer in that spirit (i.e. rather than write the code, point you in the right direction).
First, it's not really clear what you mean by "subset". Are you talking about contiguous runs of elements from the array? Or do you literally mean treating the array as an unordered set, from which you examine every possible subset?
The latter is significantly harder than the former. So I'm going to assume the former for the moment.
Then, it seems you really have two different problems:
Find all subsets of the array and sum each one
For a given sum, determine whether it's in the array
The latter is fairly straightforward. If you know these arrays will always be relatively short (and hopefully they will be, otherwise "find all subsets" may take awhile :) ), you can just do a linear search every time you have a new sum to look for.
Alternatively, a more semantically straightforward approach would be to create a HashSet<int> instance once using the members of the array, and then when you want to know if the sum is in the array, just check your set.
For example:
HashSet<int> setOfValues = new HashSet<int>(array);
Then you can just write setOfValues.Contains(sum) to check whether the value held by the variable sum is contained in the array.
As for the first problem, it seems to me that you really should only need two loops:
A loop to iterate on the index of the first element of a subset. I.e. you need to enumerate all subsets, first starting with all subsets that start with element 0, then with all subsets that start with element 1, and so on.
A loop to iterate on the length of the subset. I.e. having determined the starting index for your current group of subsets, now you want to find all the actual subsets: the first has length 1, the second has length 2, and so on up to the maximum possible length (i.e. the length of the array minus the current 0-based starting index value).
Considering for a moment the alternative possibility — that you are treating the array as an unordered set — then it seems to me an obvious, if brute-force approach, would be to generate the subsets recursively.
In that approach, you would again have a loop to enumerate the subset lengths, starting with 1, up to the total length of the original set. Then, given a length, you need to pick all possible subsets.
You can do this recursively:
Given a set, iterate over the elements of the current set (passed in to your recursive method). The current element is the new element of your current subset.
If your current subset is now the correct length, sum it and compare to the original set.
Otherwise, remove the current element from the current set and recurse.
The easiest implementation of the above will create new copies of the current set for each level of recursion, to pass to the method when it calls itself. This way you don't have to worry about one level of recursion interfering with previous levels.
Do note that this is going to be practical only for relatively small initial sets. It won't take very large initial arrays before your computer doesn't have enough time or memory to complete the search of all possible subsets.
First up, you need a method that will return all subsets.
Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> getAllSubsets = null;
getAllSubsets = xs =>
(xs == null || !xs.Any())
? Enumerable.Empty<IEnumerable<int>>()
: xs.Skip(1).Any()
? getAllSubsets(xs.Skip(1))
.SelectMany(ys => new [] { ys, xs.Take(1).Concat(ys) })
: new [] { Enumerable.Empty<int>(), xs.Take(1) };
So given getAllSubsets(new[] { 1, 2, 3 }) I get:
{ }
{ 1 }
{ 2 }
{ 1, 2 }
{ 3 }
{ 1, 3 }
{ 2, 3 }
{ 1, 2, 3 }
Now's it's easy to compute the result you want.
int[] array = { 1,2,3,5,8,10,15,23};
var result =
getAllSubsets(array)
.Where(ss => array.Contains(ss.Sum()))
.Count();
I get 22.
Using a bit of Linq:
int[] array = {1, 2, 3, 5, 8, 10, 15, 23};
var subsets = new List<IEnumerable<int>>();
int counter = 0;
for (int i = 0; i < array.Length; i++)
{
for (int j = 2; j < array.Length - i; j++)
{
if (array.Contains(array.Skip(i).Take(j).ToList().Sum()))
{
counter++;
}
}
}
Console.WriteLine("Number of subsets:" + counter);
Gives you:
Number of subsets:5

Categories

Resources