I have the following problem:
I have three elements a, b and c. And also integers from 0 to 100. How can I get all the possible combinations to look like:
a 0 b 0 c 0
a 1 b 0 c 0
a 0 b 1 c 0
a 0 b 0 c 1
a 1 b 1 c 0
...
a 100 b 100 c 100
and so on? I am using C# but I am rather struggling to find the correct algorithm independently of programming language. Unfortunately I do not really understand carthesian products etc.
You say you want to
find the correct algorithm independently of programming language
So I shall try to answer this using the minimum of programming language features. The example I shall give assumes the programming language has expandable lists, arrays, arrays of arrays and the ability to shallow clone an array. These are common programming features, so hopefully this will be OK.
To solve this problem, you need to produce all the combinations of 3 sets of N integers where each set consists the integers from 0..N-1. (The set of combinations of a set of sets - which is what this is - is called the Cartesian Product of those sets.)
The solution below uses recursion, but we don't need to worry about stack overflow because the stack depth does not exceed the number of sets to combine - in this case, 3. (Normally with recursion you would try to use a stack class to manage it, but that makes the code more complicated.)
How it works:
combine() recursively iterates through all elements of each set, and at each level of recursion it begins processing the elements of the next set.
So the outer level of recursion begins iterating over all the elements of set[0], and for each element it fills in the next item of the current combination with that element.
Then: if that was the last set, the combination is complete and it is output. Otherwise: a recursive call is made to start filling in the elements from the next set.
Once we have all the combinations, we can just iterate through them and intersperse them
with a, b and c as per your requirement.
Putting this together:
using System;
using System.Collections.Generic;
namespace ConsoleApp1
{
class Program
{
static void Main()
{
var sets = createSets(3, 10);
var combinations = Combinations(sets);
foreach (var combination in combinations)
{
Console.WriteLine($"a {combination[0]} b {combination[1]} c {combination[2]}");
}
}
static int[][] createSets(int numSets, int intsPerSet)
{
int[][] sets = new int[numSets][];
// All the sets are the same, so we can just use copies of it rather than create multiples.
int[] oneSet = new int[intsPerSet];
for (int i = 0; i < intsPerSet; ++i)
oneSet[i] = i;
for (int i = 0; i < numSets; ++i)
sets[i] = oneSet;
return sets;
}
public static List<int[]> Combinations(int[][] sets)
{
var result = new List<int[]>();
combine(sets, 0, new int[sets.Length], result);
return result;
}
static void combine(int[][] sets, int set, int[] combination, List<int[]> output)
{
for (int i = 0; i < sets[set].Length; ++i)
{
combination[set] = sets[set][i];
if (set < (sets.Length - 1))
combine(sets, set + 1, combination, output);
else
output.Add((int[])combination.Clone());
}
}
}
}
Notes
This is an inefficient implementation because it returns all the combinations in one huge list. I kept it this way for simplicity (and to reduce the number of program language features required for its implementation). A better solution in C# would be to pass in an Action<int[]> to be called with each combination - then the results wouldn't need to be returned via a huge list.
This doesn't produce the results in the same order as your sample output. I have assumed that this doesn't matter!
A great Linq implementation of the Cartesian Product is presented by Eric Lippert here. I highly recommending reading it!
If the order of the output doesn't matter, this should be enough:
for(int i = 0; i <= 100; i++){
for(int j = 0; j <= 100; j++){
for(int k = 0; k <= 100; k++){
Console.WriteLine($"a {i} b {j} c {k} ");
}
}
}
OUTPUT
a 0 b 0 c 0
a 0 b 0 c 1
a 0 b 0 c 2
a 0 b 0 c 3
...
a 100 b 100 c 100
I have searched and found very many algorithms in this topic but have not found one that fits this. I have also not found anyone I managed to change so my problem is resolved.
I need a function that takes a List and then returns a List with a List of all these combinations. The lists should be combinations with all objects down to only one lone object.
Example:
fun(new List<obj> {objA, objB, objC});
Should return
public List<List<obj>> fun(List<obj> L){
...
return List{
List{objA},
List{objB},
List{objC},
List{objA, objB},
List{objA, objC},
List{objB, objC},
List{objA, objB, objC};
}
And I do not know in advance how long the list will be.
I know the mathematical expression
n! / k! (n-k)! + n! / (k-1)! (n-(k-1))! + ... + n! / 1! (n-1)!
Where n is the number of available objects and k is the number of them you want to combine.
The result of this calculation will be the number of List< obj > that will be included in the returned List
But, as I said, I have not managed to get something sensible in code.
I use c# so I prefer answers in this language. But all help is welcome.
I have looked at so many algorithms that I now get more confused than it helps.
You can use an integral value to count up through all the combinations.
Then, for each value, check each bit in the number. Each 1 bit means that the corresponding item is included in the combination.
If you think about how binary numbers work, you'll understand how this algorithm works. For example, for 3 items, you will have a 3-bit binary number that goes from 001 to 111 with each of the 3 bits corresponding to one of the items, like so:
001
010
011
100
101
110
111
You should be able to see how we can use each bit to decide whether or not the corresponding item is included in that combination.
Here's a sample implementation - this works if the number of items is <= 32:
public static IEnumerable<IEnumerable<T>> Combinations<T>(IList<T> items)
{
return Combinations(items.Count).Select(comb => comb.Select(index => items[index]));
}
public static IEnumerable<IEnumerable<int>> Combinations(int n)
{
long m = 1 << n;
for (long i = 1; i < m; ++i)
yield return bitIndices((uint)i);
}
static IEnumerable<int> bitIndices(uint n)
{
uint mask = 1;
for (int bit = 0; bit < 32; ++bit, mask <<= 1)
if ((n & mask) != 0)
yield return bit;
}
You can test this with, for example, a list of characters A..E:
IList<char> test = "ABCDE".ToList();
foreach (var comb in Combinations(test))
Console.WriteLine(string.Concat(comb));
This outputs:
A
B
AB
C
AC
BC
ABC
D
AD
BD
ABD
CD
ACD
BCD
ABCD
E
AE
BE
ABE
CE
ACE
BCE
ABCE
DE
ADE
BDE
ABDE
CDE
ACDE
BCDE
ABCDE
If you want to turn the IEnumerable<IEnumerable<T>> into a List<List<T>>, just do the following:
List<List<T>> list = Combinations(inputList).Select(x => x.ToList()).ToList();
For example, for the List<char> above do this:
List<List<char>> list = Combinations(test).Select(x => x.ToList()).ToList();
I'm not sure about performance, but from a readability point of view this is the best I came up with - using a couple of nested loops and linq's Skip and Take:
var source = new List<int>() { 1, 2, 3 };
var target = new List<List<int>>();
for(var i = 0; i < source.Count; i++)
{
for(var j = i; j < source.Count; j++)
{
target.Add(new List<int>(source.Skip(i).Take(source.Count - j)));
}
}
You can see a live demo on rextester
So, i have this array which contains a bunch of numbers. I want to always take 3 of those chars and make one integer out of them. I haven't found anything on this yet.
here is an example:
string number = "123456xyz";
The string is what I have, these integers are what I want
int goal1 = 123;
int goal2 = 456;
int goaln = xyz;
It should go through all the chars and always split them into groups of three. I think foreach() is going to help me, but im not quite sure how to do it.
Something like this:
var goals = new List<int>();
for (int i = 0; i + 2 < number.Length; i += 3)
{
goals.Add(int.Parse(number.Substring(i,3)));
}
This has no error checking but it shows the general outline. Foreach isn't a great option because it would go through the characters one at a time when you want to look at them three at a time.
var numbers = (from Match m in Regex.Matches(number, #"\d{3}")
select m.Value).ToList();
var goal1 = Convert.ToInt32(numbers[0]);
var goal2 = Convert.ToInt32(numbers[1]);
...
Lets say I have collection of n workers. Lets say there are 3:
John
Adam
Mark
I want to know when they have to clean the office. If I set int cleanDays = 3 it would be something like that:
//Day of month;worker
1;John
2;John
3;John
4;Adam
5;Adam
6;Adam
7;Mark
8;Mark
9;Mark
10;John
11;John
.
.
.
If I set cleanDays = 1 it would be:
1;John
2;Adam
3;Mark
4;John
5;Adam
.
.
.
And so on.
I already managed something like this:
int cleanDays = 6;
for (int day=1; day<30;day++) { //for each day
int worker = (day-1 % cleanDays)%workers.Count; //get current worker (starting from index 0)
for (int times=0; times< cleanDays; times++) //worker do the job `cleanDays` times
Console.WriteLine(day++ + ";" +workers[worker].Name);
}
This is not working properly, because it gaves me 34 days. That because of day++ in first loop. But if I delete day++ from first loop:
for (int day=1; day<30;) { //for each day
int worker = (day-1 % cleanDays)%workers.Count; //get current worker (starting from index 0)
for (int times=0; times< cleanDays; times++) //worker do the job `cleanDays` times
Console.WriteLine(day++ + ";" +workers[worker].Name);
}
It is giving output only with first worker. When I debugged I saw that:
int worker = (day-1 % cleanDays)%workers.Count;
and worker was equal to 0 everytime. That means:
(20-1%6)%3 was equal to 0. Why does that happen?
UPDATE: I just read your question more carefully and realized you were not asking about the actual code at all. Your real question was:
That means: (20-1%6)%3 was equal to 0. Why does that happen?
First of all, it doesn't. (20-1%6)%3 is 1. But the logic is still wrong because you have the parentheses in the wrong place. You meant to write
int worker = (day - 1) % cleanDays % workers.Count;
Remember, multiplication, division and remainder operators are all higher precedence than subtraction. a + b * c is a + (b * c), not (a + b) * c. The same is true of - and %. a - b % c is a - (b % c), not (a - b) % c.
But I still stand by my original answer: you can eliminate the problem entirely by writing a query that represents your sequence operations, rather than a loop with a bunch of complicated arithmetic that is easy to get wrong.
Original answer follows.
Dmitry Bychenko's solution is pretty good but we can improve on it; modular arithmetic is not necessary here. Rather than indexing into the worker array, we can simply select-many from it directly:
var query = Enumerable.Repeat(
workers.SelectMany(worker => Enumerable.Repeat(worker, cleanDays)),
1000)
.SelectMany(workerseq => workerseq)
.Select((worker, index) => new { Worker = worker, Day = index + 1})
.Take(30);
foreach(var x in query)
Console.WriteLine($"Day {x.Day} Worker {x.Worker}");
Make sure you understand how this query works, because these are core operations of LINQ. We take a sequence of workers,
{A, B, C}
This is projected onto a sequence of sequences:
{ {A, A}, {B, B}, {C, C} }
Which is flattened:
{A, A, B, B, C, C}
We then repeat that a thousand times:
{ { A, A, B, B, C, C },
{ A, A, B, B, C, C },
...
}
And then flatten that sequence-of-sequences:
{ A, A, B, B, C, C, A, A, B, B, C, C, ... }
We then select-with-index into that flattened sequence to produce a sequence of day, worker pairs.
{ {A, 1}, {A, 2}, {B, 3}, {B, 4}, ... }
Then take the first 30 of those. Then we execute the query and print the results.
Now, you might say isn't this inefficient? If we have, say, 4 workers, we put each on 5 days, and then we repeat that sequence 1000 times; that makes a sequence with 5 x 4 x 1000 = 20000 items, but we only need the first 30.
Do you see what is wrong with that logic?
LINQ sequences are constructed lazily. Because of the Take(30) we never construct more than 30 pairs in the first place. We could have repeated it a million times; doesn't matter. You say Take(30) and the sequence construction will stop constructing more items after you've printed 30 of them.
But don't stop there. Ask yourself how you can improve this code further.
The bit with the days as integers seems a bit dodgy. Surely what you want is actual dates.
var start = new DateTime(2017, 1, 1);
And now instead of selecting out numbers, we can select out dates:
...
.Select((worker, index) => new { Worker = worker, Day = start.AddDays(index)})
...
What are the key takeaways here?
Rather than messing around with loops and weird arithmetic, just construct queries that represent the shape of what you want. What do you want? Repeat each worker n times. Great, then there should be a line in your program somewhere that says Repeat(worker, n), and now your program looks like its specification. Now your program is more likely to be correct. And so on.
Use the right data type for the job. Want to represent dates? Use DateTime, not int.
I would use a while loop, and use some tracking variables to keep track of which worker you are at and how many clean-times are left for that worker. Something like this:
const int cleanTime = 3; // or 1 or 6
var workers = new [] { "John", "Adam" , "Mark" }
var day = 1;
var currentWorker = 0;
var currentCleanTimeLeft = cleanTime;
while (day <= 30) {
Console.WriteLine("{0};{1}", day, workers[currentWorker].Name);
currentCleanTimeLeft--;
if (currentCleanTimeLeft == 0) {
currentCleanTimeLeft = cleanTime;
currentWorker++;
if (currentWorker >= workers.Length)
currentWorker = 0;
}
day++;
}
A very basic solution, no division or arithmatics required.
The second loop is unnecessary, it simply messes up your day.
int cleanDays = 6;
for (int day = 1; day <= 30; day++)
{
int worker = ((day-1) / cleanDays) % workers.Count;
Console.WriteLine(day + ";" + workers[worker].Name);
}
Example on Fiddle
The basic idea is to give each individual day an numerical value - DateTime.Now.DayOfYear is a good choice, or just a running count - and map that numerical value to an index in the Worker array.
The main logic is in the workerIndex line below:
It takes the day number and divides it by cleanDays. This means that each x days is mapped to the same workerIndex.
It takes the workerIndex and does a modulo operation on it (%) on the count of workers. This causes the workerIndex to by cyclical, iterating endlessly over all workers.
string[] workers = new string[] {"Mike", "Bob", "Hank"};
int cleanDays = 6;
for (int dayNum = 0 ; dayNum < 300 ; dayNum++)
{
var workerIndex = (dayNum / cleanDays) % workers.Length; // <-- LOGIC!
Console.WriteLine("Day {0} - Cleaner: {1}", dayNum, workers[workerIndex]);
}
I suggest modulo arithmetics and Linq:
List<Worker> personnel = ...
int days = 30;
int cleanDays = 4;
var result = Enumerable.Range(0, int.MaxValue)
.SelectMany(index => Enumerable
.Repeat(personnel[index % personnel.Count], cleanDays))
.Select((man, index) => $"{index + 1};{man.Name}")
.Take(days);
Test:
Console.Write(string.Join(environment.NewLine, result));
Output:
1;John
2;John
3;John
4;John
5;Adam
6;Adam
7;Adam
8;Adam
9;Mark
...
24;Mark
25;John
26;John
27;John
28;John
29;Adam
30;Adam
you could create a sequence function:
public static IEnumerable<string> GenerateSequence(IEnumerable<string> sequence, int groupSize)
{
var day = 1;
while (true)
{
foreach (var element in sequence)
{
for (var i = 0; i < groupSize; ++i)
{
yield return $"{day};{element}";
day++;
}
}
}
}
usage:
var workers = new List<string> { "John", "Adam", "Mark" };
var cleanDays = 3;
GenerateSequence(workers, cleanDays).Take(100).Dump();
I would do something like this:
var cleanDays = 6; // Number of days in each shift
var max = 30; // The amount of days the loop will run for
var count = workers.Count(); // The amount of workers
if(count == 0) return; // Exit If there are no workers
if(count == 1) cleanDays = max; //See '3.' in explanation (*)
for(var index = 0; index < max; index++){
var worker = (index / cleanDays ) % count;
var day = index % cleanDays ;
Console.WriteLine(string.format("Day {0}: {1} cleaned today (Consecutive days cleaned: {2})", index+1, workers[worker].Name ,day));
}
Explanation
By doing index / cleanDays you get the amount of times of worker shifts. But it is possible that the shifts are more than the amount of workers in which case you would want to get the reminder (shifts % amount of workers).
To get how many consecutive days the worker has worked so far you simply need to get the remainder of the first division done above. (index / cleanDays ).
Finally as you can see I get the count of the array before I enter the loop for 3 reasons:
To only read it once. And save some time.
To exit if the method if the array is empty
To check if there is only one worker left. In which case that worker won't have a break and will be working from day 1 until day 'max' therefore I set the cleanDays to max. *
I want to easily pre-populate a single dimensional string array which I am calling "letters" with the values:
AAAAAA
AAAAAB
AAAAAC
AAAAAD
..
..
ZZZZZX
ZZZZZY
ZZZZZZ
Thats 165 million combinations in order.
The idea being I need to then be able to ask for any particular combination of 6 characters such as BBCHHJ and use Array.Index to return the element of the array it is in.
I have the second bit fine:
String searchFor;
Console.Write("Enter a string value to search for: ");
searchFor = Console.ReadLine();
int indexValue = Array.IndexOf(letters, searchFor);
Console.WriteLine("The value you are after is in element index: " + indexValue);
Console.ReadLine();
But I have no idea how to easily initialise the letters array with all those combinations, in order!
A variation on Jakub's answer which should be a bit more efficient:
int result = s
.Select(c => c - 'A') // map 'A'-'Z' to 0-25
.Aggregate(0, (total, next) => total * 26 + next); // calculate the base 26 value
This has the advantage of avoiding the Reverse and the separate Sum, and the powers of 26 don't have to be calculated from scratch in each iteration.
Storing 308 million elements in array and searching them is not the best solution, rather calculate the index at runtime. I have created a code sample:
string input = "ZZZZZZ";
//default values
string alphabets_s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] alphabets = alphabets_s.ToCharArray();
int result = 1; //starting with "one" because zero will make everything zero
//calculating index
for (int i = 0; i < input.Length; i++)
{
//get character index and add "1" to avoid multiplication with "0"
int index = Array.IndexOf(alphabets, input[i]) + 1;
//multiply it with the current result
result *= index;
}
//subtract 1 from final result, because we started it with 1
result--;
PS: I did just basic testing, please inform me if you find anything wrong in it.
As I wrote in a comment, what you're trying to achieve is basically conversion from base 26 number.
The first step is to convert the string to a list of digits. Then just multiply by powers of 26 and add together:
var s = "AAAABB";
var result = s
.Select(c => c - 'A') //map characters to numbers: A -> 0, B -> 1 etc
.Reverse() //reverse the sequence to have the least significant digit first
.Select((d, i) => d * Math.Pow(26, i))
.Sum();