Example:
a = "56 65 74 100 99 68 86 180 90", ordered by numbers weights becomes: "100 180 90 56 65 74 68 86 99"
When two numbers have the same "weight", let us class them as if they were strings and not numbers: 100 is before 180 because its "weight" (1) is less than the one of 180 (9) and 180 is before 90 since, having the same "weight" (9) it comes before as a string.
All numbers in the list are positive numbers and the list can be empty.
My tests:
[TestMethod]
public void Test1()
{
Assert.AreEqual("2000 103 123 4444 99",
WeightSort.orderWeight("103 123 4444 99 2000"));
}
[TestMethod]
public void Test2()
{
Assert.AreEqual("11 11 2000 10003 22 123 1234000 44444444 9999",
WeightSort.orderWeight("2000 10003 1234000 44444444 9999 11 11 22 123"));
}
My class to calculate the order of the weights:
public class WeightSort
{
public static string orderWeight(string strng)
{
List<int> list = strng.Split(' ').Select(Int32.Parse).OrderBy(i => i).ToList();
List<int> SumofNums = new List<int>();
List<string> SumandNums = new List<string>();
List<string> SumandNums2 = new List<string>();
List<string> Nums = new List<string>();
foreach (var itm in list)
{
int num = (int)GetSumOfDigits(itm);
SumofNums.Add(num);
SumandNums.Add(itm + "," + num);
}
SumofNums = SumofNums.OrderBy(i => i).ToList();
string txt = "";
foreach (var itm in SumofNums)
{
var item = itm.ToString();
if (!Nums.Contains(item))
{
foreach (var itm2 in SumandNums)
{
var itm3 = itm2.Split(',');
if (item == itm3[1])
{
SumandNums2.Add(itm2);
if (string.IsNullOrEmpty(txt))
txt = itm3[0];
else
txt = txt + " " + itm3[0];
}
}
Nums.Add(item);
}
}
return txt;
}
static long GetSumOfDigits(long n)
{
long num2 = 0;
long num3 = n;
long r = 0;
while (num3 != 0)
{
r = num3 % 10;
num3 = num3 / 10;
num2 = num2 + r;
}
return num2;
}
}
I can handle if there is only one but not duplicates.
Please help me rewrite my class so it can handle the duplicates also..
Sum of digits:
string weights = "103 123 4444 99 2000";
1) 2000, digit sum = 2;
2) 103, digit sum = 4;
3) 123, digit sum = 6;
4) 4444, digit sum = 16;
5) 99, digit sum = 18;
the correct order is "2000 103 123 4444 99"
You can use Linq if sorting by weight means
by sum of digits
lexicographically ("as strings")
the implementation
String a = "56 65 74 100 99 68 86 180 90";
// 100 180 90 56 65 74 68 86 99
String result = String.Join(" ", a
.Split(' ')
.OrderBy(item => item.Sum(ch => ch - '0')) // sum of digits
.ThenBy(item => item)); // lexicographic ("as string")
Try this:
var input = "103 123 4444 99 2000";
var sorted = input.Split(' ').OrderBy(s => s.Sum(c => c - '0')).ThenBy(s => s);
var result = string.Join(" ", sorted);
Addition: I realize now that Dmitry's answer had evolved into the same as mine before I posted mine.
New addition: If you find that s.Sum(c => c - '0') is like a hack, you can be using System.Globalization; and say s.Sum((Func<char, int>)CharUnicodeInfo.GetDecimalDigitValue) instead.
You can validate in the lambda. For example:
var sorted = input.Split(' ')
.OrderBy(s => s.Sum(c => { if (c < '0' || c > '9') { throw new ArgumentOutOfRangeException("c", "Unexpected character."); } return c - '0'; }))
.ThenBy(s => s);
You can also do this by creating a comparer which tells you whether a value is greater than or less than another value and can then be used. The code largely speaks for itself:
void Main()
{
var strings = new List<string>("2000 10003 1234000 44444444 9999 11 11 22 123".Split(' '));
strings.Sort(new MyComparer());
Console.WriteLine(String.Join(" ", strings));
}
public class MyComparer : IComparer<string>
{
public int Compare(string a, string b)
{
var aWeight = GetWeight(a);
var bWeight = GetWeight(b);
if (aWeight==bWeight)
{
return String.Compare(a,b);
}
else
{
return aWeight < bWeight ? -1 : 1;
}
}
private int GetWeight(string number)
{
var weight = 0;
foreach(var digit in number)
{
weight+=Int32.Parse(digit.ToString());
}
return weight;
}
}
The key thing is the MyComparer class which defines a single public method that takes two values in. It gets the weights of the objects and if they are the same it falls back to string comparison.
This comparer can then be passed to a sort function such as that of List<T> to then do the sorting.
This is much lengthier but I thought it worth sharing as it is a little more reusable (eg if you do this in a lot of places in your code you can have your logic in a single class) and it can sometimes be a bit more readable.
I also note I am not a fan of ch - '0' as a way of getting the int value of a character since it is not always obvious at a glance what it does if you don't know the trick. Also in the event of non numeric characters it will still do things, just not necessarily anything sensible. Mine will just throw a good old fashioned exception that can be caught if you pass it any non-numeric data.
I found this solution pretty short and clear:
var orderedNumbers = "56 65 74 100 99 68 86 180 90".Split(' ')
.OrderBy(GetWeight)
.ThenBy(x => x);
var result = String.Join(" ", orderedNumbers);
This will first calculate the weight from any given number and sort by this value. If it´s equal the ThenBy-clause comes to the play and furtherly orders the result by performing a string-comparison (as the values returned by the first OrderBy is a list of strings).
With
int GetWeight(string number)
{
return number.Sum(x => CharUnicodeInfo.GetDecimalDigitValue(x));
}
Related
Console.WriteLine(" Even Table \n");
int MaxNumber = 100;
int EvenNumbers = 0;
int i;
for (i = 0; i <=MaxNumber; i+=2)
{
if (i % 2 == 0)
{
EvenNumbers = i;
}
Console.Write(EvenNumbers);
}
OUTPUT:
Even Table
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 70 72 74 76 78 80 82 84 86 88 90 92 94 96 98 100
I am making a program that displays the even numbers between 2 and 100 inclusively. I am able to display the even numbers, although the formatting for the output is in a straight line due to the Console.Write, is there a string format that can I use to have the output display each even number, but cut to a new line every interval of 20? So it would look like:
1-20
20-40
40-60
ETC
Less lines with Linq! :p
foreach (var even in Enumerable.Range(2, 100).Where(i => i % 2 == 0))
Console.Write(even % 20 != 0 ? even.ToString() + " " : even.ToString() + "\n");
Use this:
for (i = 0; i <=MaxNumber; i+=2)
{
EvenNumbers = i;
Console.Write(EvenNumbers+" ");
if(i%20==0){
Console.WriteLine();
}
}
You do not need condition if (i % 2 == 0) because your step is 2.
In complement for Luis solution, you can do it easily with this code :
foreach (var item in Enumerable.Range(1, 100).Where(o => o % 2 == 0).GroupBy(o => (int)(o / 20.01)))
{
Console.WriteLine(string.Join(" ", item.ToArray()));
}
Loop on group by '20' filtered by modulo 2 enumeration of int and print it in one line with string.join
You need to cast the groupby if you want your first number are 20, 40, 60... else it starts with 22, 42, 62...
Hope this helps
Try below; It will consider 0 as well; Otherwise 0 will be isolated.
Console.WriteLine(" Even Table \n");
int MaxNumber = 100;
int EvenNumbers = 0;
int i;
for (i = 0; i <= MaxNumber; i += 2)
{
if (i % 2 == 0)
{
EvenNumbers = i;
}
Console.Write(" ");
Console.Write(EvenNumbers);
if (i % 20 == 0 && i>0)
{
Console.WriteLine();
}
}
Here is a different approach using Enumerable.Range and String.Join:
int MaxNumber = 100;
// create a list of all even numbers
List<int> even_list = Enumerable.Range(0, MaxNumber+1).Where(x => x % 2 == 0).ToList();
// for the amount of numbers to be displayed in a line
int numbers_in_single_line = 10
for (int i = 1; i <= even_list.Count; i += numbers_in_single_line)
{
Console.WriteLine(String.Join(" ", even_list.Skip(i).Take(numbers_in_single_line )));
}
Skip() and Take() allow you to select values from the list at certain positions
I have a list of list of string in order to group the string with the number of '1' like string = "00000" belongs to the first group and string = "00001" belongs to the second group. ALl String are equal length. Now I compare the first group to the second group and second group to third group and soon...like in the Image. The First element in the first group is compared to all elements of the second group. Until every string are compared. Is There a way to speed up the performance of my program? So I can Achieved 32000 string with 15 Length.
Edit
Sorry for the past post.After reading it i realize I was to dumb asking like that.
The goal of the program was a simplifier. Based on the Quine–McCluskey algorithm
Consider
000
001
010
011
100
101
110
111
I group them by number of 1
000
001
010
100
011
101
110
111
Then I compare each string from the group to the next group
group 1
000
group 2
001
010
100
group 3
011
101
110
group1 -> group2
------------------
000 -> 001 = 00-
000 -> 010 = 0-0
000 -> 100 = -00
------------------
group2 ->group3
--------------------
001 -> 011 = 0-1
001 -> 101 = -01
001 -> 110 = no output
010 -> 011 = 01-
010 -> 101 = no output
010 -> 110 = -10
100 -> 011 = no output
100 -> 101 = 10-
100 -> 110 = 1-0
---------------------
etc.
then group the output again by number of 1 and compare them again until no strings can be compared.
I need to achieve a 15 variable but it take for ever for the program to finish.Any Idea how to speed it up. I was testing it on threading but just a little improvement.
Number of Strings: 2048 Length of variable: 11 Time: 10 minutes
Need to Achieved
Number of Strings: 32767 Length of variable: 15 Time: cannot be achieved
List<List<string>> ImplicantsByOneFinal = new List<List<string>>();
List<List<string>> TermsByOne = new List<List<string>>();
is there a way or algorithm to improve this code. it becomes slower on 11 to 15 variables.
bool CombineAndGroup(List<List<string>> ImplicantsByOne)
{
TermsByOne = new List<List<string>>();
int combined = 0;
for (int i = 0; i < ImplicantsByOne.Count - 1; i++)
{
List<string> termsGrouped = new List<string>();
for (int j = 0; j < ImplicantsByOne[i].Count; j++)
{
int combination = 0;
int num1 = Convert.ToInt32((ImplicantsByOne[i][j]).Replace('-','0'), 2);
for (int k = 0; k < ImplicantsByOne[i + 1].Count; k++)
{
int num2 = Convert.ToInt32((ImplicantsByOne[i + 1][k]).Replace('-', '0'), 2);
int num3 = num2 - num1;
double num4 = Math.Log((double)num3, (double)2);
if (((num4 % 1) == 0) && (num3 > 0) && (Esum(ImplicantsByOne[i][j]) == Esum(ImplicantsByOne[i + 1][k])))
{
string combinedMinterm = CompareString(ImplicantsByOne[i][j], ImplicantsByOne[i + 1][k]);
if (!termsGrouped.Contains(combinedMinterm))
{
termsGrouped.Add(combinedMinterm);
}
}
}
}
if (termsGrouped.Count > 0)
{
combined += termsGrouped.Count;
}
TermsByOne.Add(termsGrouped);
}
return (combined > 0) ? true : false;
}
private int Esum(String binCode)
{
binCode = binCode.Replace('1','0');
binCode = binCode.Replace('-', '1');
int esum = Convert.ToInt32(binCode, 2);
return esum;
}
//Purpose of CompareString is to compare two string and change the unique char to '-'
//like 000 and 001 = 00-
private string CompareString(string str1, string str2)
{
if (str1 == str2)
{
CountCompareStringLoops++;
return str1;
}
else
{
if (str1.Length == 1)
{
return "-";
}
int halflength = str1.Length / 2;
return CompareString(str1.Substring(0, halflength), str2.Substring(0, halflength)) + CompareString(str1.Substring(halflength), str2.Substring(halflength));
}
}
Main Program
MintermsByOne = Loaded with string 000 001 and so on
CombineAndGroup(MintermsByOne);
ImplicantsByOneFinal = TermsByOne;
while (CombineAndGroup(TermsByOne))
{
ImplicantsByOneFinal = TermsByOne;
}
Output ImplicantsByOneFinal
It's not really clear what you're trying to achieve, to be honest... your description doesn't match your code. (Your code never mentions the character '1', for example. The fact that you never use the result of calling CompareString is suspicious too.) LINQ should make implementing your description of "group the string with the number of '1' " easy and efficient:
var grouped = strings.GroupBy(x => x.Count(c => c == '1'));
That will only count the number of '1' characters in each string once. You never need to compare any string with another one.
If this isn't what you're actually trying to do, you need to clarify what your actual aim is.
I don't know how to write C#, but I want to help. So my code is given in Java.
1. I think == is an O(n) operation, your CompareString may be O(nlgn) where n = str1.Length. Use a simpler and faster O(n) way and see if the time decreases:
private String CompareString(String str1, String str2) {
StringBuilder sb = new StringBuilder(str1.length());
for (int i = 0; i < str1.length(); i++) {
if (str1.charAt(i) == str2.charAt(i))
sb.append(str1.charAt(i));
else
sb.append('-');
}
return sb.toString();
}
2. Well, I found out there are a lot of ToInt32. Calculate the result of all strings in ImplicantsByOne at once and use it later. So does Esum.
3. To check if num3 is a power of two:
private boolean isPowerOfTwo(int x) {
return (x > 0 && (x & (x - 1)) == 0);
}
Input Value can be from A to ZZZ (only alphabetical, no numeric characters) how can I validate a from and to field.
Where the input can be A or AA or AAA
B > A
BB > A
BBB > A
BBB < B
BBB < BB
DD > C
but then D should be < CC fails because it is not a lexicographical order
I was thinking check the length first because if the from length is less than to length then it will always be less. If equal in length then an alphabetical check. Then I come unstuck.
Not simple lexicographical order because three possiable groups single, double, triple chars single group lower than double and triple group and double lower than triple group not just alphabetical.
have you thought about using a regexp? \b[A-Z]{1,3}\b
You can do the following: Imagine the String AAA as a number, saying A*26^2 + A*26^1 + A*26^0
(Base 26, because there are that much letters)
Split the String, Cast values A to Z to 1 to 26 (WhiteSpace in front = 0) and you are done:
A = 0*26^2 + 0*26^1 + 1*26^0 => 1
B = 2 => 2
...
Z = 26 => 26
AA = 1 * 26^1 + 1 => 27
...
ZZ = 26*26^1 + 26 = 702
...
ZZZ = 26*26^2 + 26*26^1 + 26 => 18278
wrap it Like
public int LetterCodeToInt(String LetterCode)
{
//fill up whitespaces in front.
String s = LetterCode.PadLeft(3, '_').ToUpper();
int value = 0;
int k = s.Length -1;
for (int i = 0; i < s.Length; i++)
{
if (s[i] != '_')
{
//ASCII "A" is 65, subtract 64 to make it "1"
value += (((int)s[i]) - 64) * Convert.ToInt32(Math.Pow(26, k));
}
k--;
}
return value;
}
and you can do:
if (LetterCodeToInt("AAA") > LetterCodeToInt("AZ")){
}
string from = "BB";
string to = "AAA";
bool valid = string.Compare(from, to) < 0; // false
So it works already in lexicographical order. Demo
You're on the right track. Create a custom comparer that checks the length first. For example:
public class MyComparer : IComparer<string>
{
public int Compare(string x, string y)
{
if (x.Length < y.Length) return -1;
if (x.Length > y.Length) return 1;
return Comparer.Default.Compare(x, y);
}
}
I've got this - possibly trivial - loop/combinations problem similar to binary combinations. I don't know how to approach it efficiently. Consider this scenario, I need unique loop to pass through all these combinations in a sequence:
Round ABC
01. 000 <- values of A=0, B=0, C=0
02. 001
03. 010
04. 011
05. 100
06. 101
07. 110
08. 111
09. 002
10. 012
11. 102
12. 112
13. 020
14. 021
15. 120
16. 121 <- values of A=1, B=2, C=1
17. 022
18. 122
19. 220
20. 221
21. 222
Except there are 12 letters (A-L), and also the "bit" size is not just 0,1 or 2 but any integer number (from 0 possibly up-to 1000 or 1024, not to make it crazy). I know it's a huge load of combinations, but I'll just scrap just top few that also fulfill my other conditions. So no need to worry about computational madness.
Disclaimer: The order has to be exactly as shown above. NOT a multiple FOR loops going first 0-1024 for C, then B.
Thanks in advance, I just can't seem to find the way to "algorithm it".
Update: Added whole sequence for combinations of ABC/012
regards,
Kate
Explanation:
I've encountered this problem when trying to tackle problem of analyzing sum of money for its combination of coins/notes:
For example $5001 to find out x optimal combinations.
10x $500 + 1x $1
50x $100 + 1x $1
..
Now letters (A,B,C..) correspond to a number of possible values of banknotes or coins ($1, $5,.. $100). While base correspond to a number of pieces of that banknotes/coins (for example $5001/$5000 = 1piece max.)
if I guess your sequence right, you will have it easier to generate it recursively
here an approach in Java, which should generate a sequence that matches your scenario.
I hope it helps you (maybe I add more explanation later):
public static void init() {
// define constants
final int length = 3;
final char maxValue = '3';
// define buffer
final char[] array = new char[length]; java.util.Arrays.fill(array, '0');
final boolean[] alreadySet = new boolean[length]; java.util.Arrays.fill(alreadySet, false);
// fill first digit, then let the recursion take place
for(char c = '1'; c <= (char)(maxValue); c++) {
// iterate from lowest to highest digit
for(int i = array.length-1; i >= 0; i--) {
// set value
array[i] = c;
alreadySet[i] = true;
// print value
System.out.println(new String(array));
// call recursion
recursive(array, c, i, alreadySet, length);
// unset value
alreadySet[i] = false;
array[i] = '0';
}
}
}
public static void recursive(char[] array, char lastValue, int lastIndex, boolean[] alreadySet, int leftToSet) {
// if we didn't set all digits
if(leftToSet > 0) {
// iterate from lowest to highest digit
for(int i = array.length-1; i >= 0; i--) {
// missing all digits already set
if(!alreadySet[i]) {
// count from 1 to lastValue-1
for(char c = '1'; c < lastValue; c++) {
// set value
array[i] = c;
alreadySet[i] = true;
// print value
System.out.println(new String(array));
// call recursion
recursive(array, c, i, alreadySet, leftToSet-1);
// unset value
alreadySet[i] = false;
array[i] = '0';
}
}
}
char c = lastValue;
// iterate from lowest to highest digit
for(int i = array.length-1; i > lastIndex; i--) {
// missing all digits already set
if(!alreadySet[i]) {
// set value
array[i] = c;
alreadySet[i] = true;
// print value
System.out.println(new String(array));
// call recursion
recursive(array, c, i, alreadySet, leftToSet-1);
// unset value
alreadySet[i] = false;
array[i] = '0';
}
}
}
}
A rough sketch in pseudo C#/Java:
Mapping A-L to indexes 0-11
const int[] maxvalues = { define max values for each var }
int[] counters = { initialize with 0s }
while (true)
{
for(i in 11..0)
{
counters[i]++;
if (counters[i] < maxvalues[i])
break; // for
counters[i] = 0;
}
if (counters[0] == maxvalues[0])
break; // while
print(counters.ToDisplayString());
}
(Just noted that the second sequence does not match the first sequence in OP. If OP is correct, I guess I didn't "get" the sequence)
The sequence of numbers you've described can be enumerated by counting upward from 0 in a base representation of numbers one higher than the amount of "letters" used to create your individual sequences.
One simple way to do this is to use a radix converter from base 10 which will act on a variable being incremented in a single loop from 0 to the maximum number of combinations you are looking to achieve.
Here is an implementation:
void Main()
{
for(int i=0; i< 50; i++){
Console.Write(convert(5,i));
Console.Write("\n");
}
}
string convert(int N, int M){
Stack<int> stack = new Stack<int>();
while (M >= N){
stack.Push(M %N);
M = M / N;
}
string str = M.ToString();
while(stack.Count() > 0)
str = str + stack.Pop().ToString();
return str;
}
Starting output:
0
1
2
3
4
10
11
12
13
14
20
21
22
23
24
30
31
32
33
34
40
41
42
43
44
100
101
102
103
104
Say that I have a set of numbers:
Group1 = 10, Group2 = 15, Group3 = 20, Group4 = 30
I want to output the summation of all subsets of numbers
10 + 15 = 25
10 + 15 + 20 = 45
10 + 15 + 20 + 30 = 75
15 + 20 = 35
15 + 20 + 30 = 65
20 + 30 = 50
10 + 20 = 30
10 + 30 = 40
10 + 20 + 30 = 60
... (assumed the rest is typed out)
Each of these groups will have a name, so I would want to print out the names used in the calculation before the result:
Group1 + Group2 = 25
How to do such a thing?
EDIT: to JacobM who edited tags, this is NOT homework and would appreciate an ask before you start editing it as such. I am actually at a customer site who is trying to balance a set of numbers, and the result is coming up incorrectly. My thought was to identify which group of numbers is equal to the delta between the 2 sets, and that would identify the problem directly.
Note: this would be float values, not integers.
EDIT2: added arbitrary so that it is understood that I can not just type this out once with a bunch of string.format's .. I could easily use excel at that point.
My thought was to identify which group of numbers is equal to the delta between the 2 sets, and that would identify the problem directly.
The problem "given an integer s, and a set of integers, does any non-empty subset of the set sum to s?" is known as the "subset sum problem". It is extremely well studied, and it is NP-Complete. (See this link for a related problem.)
That is to say it is amongst the hardest problems to solve in a reasonable amount of time. It is widely believed (though at present not proved) that no polynomial-time algorithm can possibly exist for this problem. The best you can do is something like O(2^n) for a set containing n elements.
(I note that your problem is in floats, not integers. It doesn't really matter, as long as you correctly handle the comparison of the calculated sum to the target sum to handle any rounding error that might have accrued in doing the sum.)
For a small number of elements -- you say you have only 15 or so in the set -- your best bet is to just try them all exhaustively. Here's how you do that.
The trick is to realize that there is one subset for each integer from 0 to 2^n. If you look at those numbers in binary:
0000
0001
0010
0011
...
each one corresponds to a subset. The first has no members. The second has just group 1. The third has just group 2. The fourth has group 1 and group 2. And so on.
The pseudocode is easy enough:
for each integer i from 1 to 2^n
{
sum = 0;
for each integer b from 1 to n
{
if the bth bit of i is on then sum = sum + group(b)
}
if sum == target then print out i in binary and quit
}
quit with no solution
Obviously this is O(n 2^n). If you can find an algorithm that always does better than O(c^n), or prove that you cannot find such an algorithm then you'll be famous forever.
The Wikipedia article has a better algorithm that gives an answer much faster most but not all of the time. I would go with the naive algorithm first since it will only take you a few minutes to code up; if it is unacceptably slow then go for the faster, more complex algorithm.
This matches every possible combination...
static void Main(string[] args)
{
Dictionary<string, float> groups = new Dictionary<string, float>();
groups.Add("Group1", 10);
groups.Add("Group2", 15);
groups.Add("Group3", 20);
groups.Add("Group4", 30);
for (int i=0; i < groups.Count - 1; i++)
{
Iterate(groups, i, 0, "");
}
Console.Read();
}
private static void Iterate(Dictionary<string, float> groups, int k, float sum, string s)
{
KeyValuePair<string, float> g = groups.ElementAt(k);
if (string.IsNullOrEmpty(s))
{
s = g.Key;
}
else
{
s += " + " + g.Key;
Console.WriteLine(s + " = " + (sum + g.Value));
}
for (int i = k + 1; i < groups.Count; i++)
{
Iterate(groups, i, sum + g.Value, s);
}
}
I've asked a question about converting an integer to byte representation to solve a problem similar to this.
Converting integer to a bit representation
Here's my 10 cents. It uses the notion that I think #DK was hinting at. You take an integer and convert it to a binary number that represents a bitmask of groups to add. 1 means add it, 0 means skip it. Its in VB but should be convertible to C# pretty easily.
'//Create the group of numbers
Dim Groups As New List(Of Integer)({10, 15, 20, 30})
'//Find the total number groups (Same as 2^Groups.Count() - 1 but reads better for me)
Dim MaxCount = Convert.ToInt32(New String("1"c, Groups.Count), 2)
'//Will hold our string representation of the current bitmask (0011, 1010, etc)
Dim Bits As String
'//Will hold our current total
Dim Total As Integer
'//Will hold the names of the groups added
Dim TextPart As List(Of String)
'//Loop through all possible combination
For I = 0 To MaxCount
'//Create our bitmask
Bits = Convert.ToString(I, 2).PadLeft(Groups.Count, "0")
'//Make sure we have got at least 2 groups
If Bits.Count(Function(ch) ch = "1"c) <= 1 Then Continue For
'//Re-initialize our group array
TextPart = New List(Of String)
'//Reset our total
Total = 0
'//Loop through each bit
For C = 0 To Bits.Count - 1
'//If its a 1, add it
If Bits(C) = "1"c Then
Total += Groups(C)
TextPart.Add("Group" & (C + 1))
End If
Next
'/Output
Trace.WriteLine(Join(TextPart.ToArray(), " + ") & " = " & Total)
Next
Outputs:
Group3 + Group4 = 50
Group2 + Group4 = 45
Group2 + Group3 = 35
Group2 + Group3 + Group4 = 65
Group1 + Group4 = 40
Group1 + Group3 = 30
Group1 + Group3 + Group4 = 60
Group1 + Group2 = 25
Group1 + Group2 + Group4 = 55
Group1 + Group2 + Group3 = 45
Group1 + Group2 + Group3 + Group4 = 75
This is a fairly classic combination problem. See this post for more details:
Algorithm to return all combinations of k elements from n
Effectively what you want to do is iterate from N-choose-1 through N-choose-N and calculate the sums of each subset.
Well as already said the key to your solution lies in getting all the possible combinations! You could put something like this in a static class to register it as an extension method:
public static IEnumerable<IEnumerable<T>> Combinations<T>(this IEnumerable<T> elements, int length = -1)
{
switch (length)
{
case -1:
foreach (var combination in Enumerable.Range(1, elements.Count()).Select(count => elements.Combinations(count)).SelectMany(c => c))
yield return combination;
break;
case 0:
yield return new T[0];
break;
default:
if (length < -1) throw new ArgumentOutOfRangeException("length");
foreach (var combination in
elements
.SelectMany((element, index) =>
elements
.Skip(index + 1)
.Combinations(length - 1)
.Select(previous => (new[] { element }).Concat(previous))))
yield return combination;
break;
}
}
... and use it like this:
static void Main(string[] args)
{
var groups = new[]
{
new Tuple<string, int>("Group1", 15),
new Tuple<string, int>("Group2", 5),
new Tuple<string, int>("Group3", 17),
};
foreach (var sum in groups
.Combinations()
.Select(x =>
string.Join(" + ", x.Select(tuple => tuple.Item1)) +
" = " +
x.Sum(tuple => tuple.Item2)))
{
Console.WriteLine(sum);
}
Console.ReadLine();
}
Output:
Group1 = 15
Group2 = 5
Group3 = 17
Group1 + Group2 = 20
Group1 + Group3 = 32
Group2 + Group3 = 22
Group1 + Group2 + Group3 = 37
Okay, the last one wasn't as straightforward as I thought. I actually tested it this time, and it gives the correct results.
void PrintInner( string output, float total, List<KeyValuePair<string, float>> children )
{
var parent = children[0];
var innerChildren = new List<KeyValuePair<string, float>>();
innerChildren.AddRange( children );
innerChildren.Remove( parent );
output += parent.Key + ":" + parent.Value.ToString();
total += parent.Value;
if( output != "" ) // Will prevent outputting "Group1:10 = 10", comment out if desired.
Console.WriteLine( output + " = " + total.ToString() );
output += " + ";
while( innerChildren.Count > 0 )
{
PrintInner( output, total, innerChildren );
innerChildren.RemoveAt( 0 );
}
}
void PrintAll()
{
var items = new List<KeyValuePair<string,float>>()
{
new KeyValuePair<string,float>>( "Group1", 10 ),
new KeyValuePair<string,float>>( "Group2", 15 ),
new KeyValuePair<string,float>>( "Group3", 20 ),
new KeyValuePair<string,float>>( "Group4", 30 )
}
while( items.Count > 0 )
{
PrintInner( "", 0, items );
items.RemoveAt( 0 );
}
}
If Group is a custom data type you can overload the +, -, *, /, =, ==, != and subsequently +=, -=, *=, and /= operators as shown here: MSDN: Operator Overloading Tutorial
If your data type is a native data type: int (Int32), long, decimal, double, or float you can do the operations you have.
To output the summation of your numbers you can use:
String.Format("{0} + {1} = {2}", Group1, Group2, (Group1 + Group2));
or
String.Format("{0} + {1} + {2} = {3}", Group1, Group2, Group3, (Group1 + Group2 + Group3));
Finally if in those examples Group is a custom data type, you would also have to overload the ToString() method so that it can display properly.
<bleepzter/>
OK, Part 2 - OO Algorithm Design?
So lets say you have the following:
public class Set: List<float>
{
public Set():base(){}
public static Set operator+(Set set1, Set set2)
{
Set result = new Set();
result.AddRange(set1.ToArray());
result.AddRange(set2.ToArray());
return result;
}
public float Sum
{
get
{
if( this.Count == 0 )
return 0F;
return this.Sum();
}
}
public override string ToString()
{
string formatString = string.Empty;
string result = string.Empty;
for(int i=0; i<this.Count; i++)
{
formatString += "{" + i.ToString() + "} + ";
}
formatString = result.TrimEnd((" +").ToCharArray()); // remove the last "+ ";
float[] values = this.ToArray();
result = String.Format(formatString, values);
return String.Format("{0} = {1}", result, this.Sum);
}
}
The object Set will have a Sum property, as well as a ToString() method that will display the sum and all of its content.