Let me first apologise for the crude manner in which I am about to phrase my question. I have been refered here by a member on another site who tells me that i am looking for a dynamic programming algorithm....my question is as follows.
I am trying to sort through some data and need to find a possible sequence in the numbers
Both sets of data include the same numbers listed in different orders as in the example below.
54 47 33 58 46 38 48 37 56 52 61 25 ………………first set
54 52 33 61 38 58 37 25 48 56 47 46 ………………second set
In this example Reading from left to right the numbers 54 52 61 and 25 occur in both sets in the same order.
So other possible solutions would be…
54 52 61 25
54 33 58 46
54 33 46
54 33 38 48 56
54 48 56…. Etc.
Although this can be done by hand, I have tons of this to get through and I keep making mistakes.
Does anyone know of an existing program or script that would output all of the possible solutions?
I understand the basic structure of c++ and virtual basic programs and should be able to cobble something together in ether but to be honest I haven’t done any serious programing since the days of the zx spectrum, so please go easy on me. my main problem however is not with the program language itself but that for some reason, I am finding it impossible to catalogue the steps required in order to complete this task in English let alone in any other language.
Darcy
Sounds like you are looking for 'all common subsequences (ACS)', which is a cousin of the (more common) longest common subsequence problem (LCS).
Here's a paper discussing ACS (though they focus on just counting subsequences, not enumerating).
To come up with an algorithm you should define the desired output more precisely. For the sake of argument, say you want the set of subsequences not contained in any longer subsequence. Then one algorithm would be:
1) Apply the DP algorithm for LCS, generating the alignment/backtrack matrix
2) Backtrack all possible LCS, marking the alignment positions visited.
3) Select the largest element of the matrix not yet marked (longest remaining subsequence)
4) Backtrack, recording the sequence and marking visited alignment positions.
5) While there exists an unmarked alignment positions, goto (3)
Backtracking in your case is complicated because you will have to visit all possible paths (called "all longest common subsequences"). You can find example implementations of LCS here, which may help to get you started.
I wrote this code and it outputs the longest common sequence. It is not super optimized though, the order is O(n*m) n-> array1 size, m-> array2 size:
private void start() {
int []a = {54, 47, 33, 58, 46, 38, 48, 37, 56, 52, 61, 25};
int []b = {54, 52, 33, 61, 38, 58, 37, 25, 48, 56, 47, 46};
System.out.println(search(a,b));
}
private String search(int[] a, int[] b)
{
return search(a, b, 0, 0).toString();
}
private Vector<Integer> search(int[] a, int[] b, int s1, int s2) {
Vector<Vector<Integer>> v = new Vector<Vector<Integer>>();
for ( int i = s1; i < a.length; i++ )
{
int newS2 = find(b, a[i], s2);
if ( newS2 != -1 )
{
Vector<Integer> temp = new Vector<Integer>();
temp.add(a[i]);
Vector<Integer> others = search(a, b, i+1, newS2 + 1);
for ( int k = 0; k < others.size(); k++)
temp.add( others.get(k));
v.add(temp);
}
}
int maxSize = 0;
Vector<Integer> ret = new Vector<Integer>();
for ( int i = 0; i < v.size(); i++)
if ( v.get(i).size() > maxSize )
{
maxSize = v.get(i).size();
ret = v.get(i);
}
return ret;
}
private int find(int[] b, int elemToFind, int s2) {
for ( int j = s2; j < b.length; j++)
if ( b[j] == elemToFind)
return j;
return -1;
}
Related
If I have a vec, how can I search this to find whether it contains another vec - and return the index where this subvec begins?
let mut haystack = vec!(0, 0, 0, 1, 48, 120, 49, 49, 1, 0);
let mut needle = vec!(48, 120, 49, 49);
Such that it returns 4 (the starting index of this subset in the original) (or rather, it would return a Result which contains 4 in this case - and which would error if it is not found at all).
This is a classic string search problem. #Willem Van Onsem suggested the KMP algorithm, but you should start with the naive algorithm.
For every index of haystack, try to compare the string of the same length as needle and starting at this index in haystack to needle itself.
Have a look at this:
0 0 0 1 48 120 49 49 1 0
48 120 49 49
x fail
48 120 49 49
x fail
48 120 49 49
x fail
48 120 49 49
x fail
48 120 49 49
- - - - match!
x means that the elements are different, - that they are the same. On every x, shift to the next element of haystack (that's the difference with KMP which may shift more than one element at once).
In Rust, you will write something like:
fn find1(haystack: &Vec<i32>, needle: &Vec<i32>) -> i64 {
for i in 0..haystack.len()-needle.len()+1 { // last indices of haystack are too far right to get a match
let mut j = 0;
while j < needle.len() { // check every char of needle
if needle[j] != haystack[i+j] { // doesn't match
break; // try the next i
}
j += 1; // else: match so far
}
if j == needle.len() { // no break: a full match was found
return i as i64;
}
}
return -1; // not a single full match
}
Of course, you can use some of Rust features to shorten the code (and avoid the C-like style above):
fn find2(haystack: &Vec<i32>, needle: &Vec<i32>) -> Option<usize> {
for i in 0..haystack.len()-needle.len()+1 {
if haystack[i..i+needle.len()] == needle[..] {
return Some(i);
}
}
None
}
Or the functional style if you prefer:
fn find3(haystack: &Vec<i32>, needle: &Vec<i32>) -> Option<usize> {
(0..haystack.len()-needle.len()+1)
.filter(|&i| haystack[i..i+needle.len()] == needle[..]).next()
}
If you understand the naive algorithm and its naive implementation, you can move to faster algorithms.
I would use the windows iterator like:
fn find(haystack: &Vec<i32>, needle: &Vec<i32>) -> Option<usize> {
for (position, window) in haystack.windows(needle.len()).enumerate() {
if window == needle {
return Some(position);
}
}
None
}
This question has been bugging me for days now, and I am at a loss as how to solve it. I have tried very hard to solve it on my own, but now I would just very much appreciate some help and a pointer in the right direction.
Problem:
Given a set of numbers, and the maximum limits for which each number can be greater than or less than the following number, determine the number of valid orderings of the numbers according to the limits.
Example:
Numbers: 20, 30, 36, 40
Max amount that a number can be greater than the following number: 16
Max amount that a number can be less than the following number: 8
Here there would be 3 valid orderings:
36 40 30 20
40 36 30 20
40 30 36 20
I have devised a way to generate all valid permutations using recursion and trees, but unfortunately it takes far too long in cases in which there are many valid orders of the list (approaches n! run time I believe). I feel as if there is a quicker, more mathematical way of solving this using combinatorics that I am just not seeing. Any advice would be greatly appreciated, thank you!
EDIT:
Here's the code for the permutation algorithm I came up with. The last part of the code tests it out with the sample I gave above. It is written in Python 3.6.
class block:
def __init__(self, val, children):
self.val = val
self.children = children
# Gets all the possible children of the current head within the limits
def get_children(head, nums, b, visited, u, d):
global total
if all(visited):
total += 1
return
for i in range(b):
if not visited[i]:
if head.val - nums[i] <= d and nums[i] - head.val <= u:
head.children.append(block(nums[i], []))
visited[i] = True
get_children(head.children[-1], nums, b, visited, u, d)
visited[i] = False
# Display all the valid permutations of the current head
def show(head, vals, b):
vals.append(head.val)
if head.children == [] and len(vals) == b:
print(*vals)
return
for child in head.children:
show(child, vals[:], b)
# Test it out with the sample
b, nums, u, d = 4, [20, 30, 36, 40], 8, 16
visited = [False for x in range(b)]
total = 0
heads = []
for i in range(b):
heads.append(block(nums[i], []))
visited[i] = True
get_children(heads[-1], nums, b, visited, u, d)
visited[i] = False
show(heads[-1], [], b)
print(total)
This prints:
36 40 30 20
40 30 36 20
40 36 30 20
3
Trying your approach with 10 equal numbers resulted in a run-time of 35 seconds.
The first thing I noticed is that the function only needs the last entry in the list head, so the function can be simplified to take an integer instead of a list. The following code has three simplifications:
Pass in an integer for head instead of a list
Change total to be a return value instead of a global
Avoid storing the children (as only the count of orderings is required)
The simplified code looks like:
def get_children(head, nums, b, visited, u, d):
if all(visited):
return 1
t = 0
for i in range(b):
if not visited[i]:
if head - nums[i] <= d and nums[i] - head <= u:
head2 = nums[i]
visited[i] = True
t += get_children(head2, nums, b, visited, u, d)
visited[i] = False
return t
# Test it out with the sample
nums, u, d = [20, 30, 36, 40], 8, 16
b = len(nums)
visited = [False for x in range(b)]
total = 0
for i in range(b):
head = nums[i]
visited[i] = True
total += get_children(head, nums, b, visited, u, d)
visited[i] = False
print(total)
This takes 7 seconds for a list of 10 equal numbers.
The second thing I noticed is that (for a particular test case) the return value of get_children only depends on the things that are True in visited and the value of head.
Therefore we can cache the results to avoid recomputing them:
cache={}
# Gets all the possible children of the current head within the limits
def get_children(head, nums, b, visited, u, d):
if all(visited):
return 1
key = head,sum(1<<i for i,v in enumerate(visited) if v)
result = cache.get(key,None)
if result is not None:
return result
t = 0
for i in range(b):
if not visited[i]:
if head - nums[i] <= d and nums[i] - head <= u:
head2 = nums[i]
visited[i] = True
t += get_children(head2, nums, b, visited, u, d)
visited[i] = False
cache[key] = t
return t
This version only takes 0.03 seconds for a list of 10 equal number (i.e. 1000 times faster than the original.)
If you are doing multiple test cases with different values of b/u/d you should reset the cache at the start of each testcase (i.e. cache={}).
As has been noted in the comments, finding all valid permutations here is equivalent to identifying all Hamiltonian paths in the directed graph that has your numbers as vertices and edges corresponding to each pair of numbers that are permitted to follow one another.
Here's a very simple Java (IDEOne) program to find such paths. Whether this makes your problem tractable depends on the size of your graph and the branching factor.
public static void main(String[] args)
{
int[] values = {20, 30, 36, 40};
Vertex[] g = new Vertex[values.length];
for(int i=0; i<g.length; i++)
g[i] = new Vertex(values[i]);
for(int i=0; i<g.length; i++)
for(int j=0; j<g.length; j++)
if(i != j && g[j].id >= g[i].id-16 && g[j].id <= g[i].id+8)
g[i].adj.add(g[j]);
Set<Vertex> toVisit = new HashSet<>(Arrays.asList(g));
LinkedList<Vertex> path = new LinkedList<>();
for(int i=0; i<g.length; i++)
{
path.addLast(g[i]);
toVisit.remove(g[i]);
findPaths(g[i], path, toVisit);
toVisit.add(g[i]);
path.removeLast();
}
}
static void findPaths(Vertex v, LinkedList<Vertex> path, Set<Vertex> toVisit)
{
if(toVisit.isEmpty())
{
System.out.println(path);
return;
}
for(Vertex av : v.adj)
{
if(toVisit.contains(av))
{
toVisit.remove(av);
path.addLast(av);
findPaths(av, path, toVisit);
path.removeLast();
toVisit.add(av);
}
}
}
static class Vertex
{
int id;
List<Vertex> adj;
Vertex(int id)
{
this.id = id;
adj = new ArrayList<>();
}
public String toString()
{
return String.valueOf(id);
}
}
Output:
[36, 40, 30, 20]
[40, 30, 36, 20]
[40, 36, 30, 20]
I know the basic concept of the merge sort algorithm but when it comes to implementing it via recursion I am having trouble grasping how it works. From what I understand, the merge sort function splits our current array into two halves and using recursion we keep doing this until we are left with 1 element for each side.
If our array is {38, 27, 43, 3, 9, 82, 10} then our recursion will start by calling itself using the subarray (left side of the original array) and repeat the process each time, halving the array and storing the left most side until we reach 1 element:
38 27 43 3 9 82 10
38 27 43 3 <-split
<---first subroutine/recursion
38 27 <-split
<---second subroutine/recursion
38 <---only 1 element left so we return the value back to the first subroutine that called
Then in our second subroutine we move on to the next line: right = merge_sort(right) which again calls itself to split the subarray and storing the right most side:
38 27 <-split
<---second subroutine/recursion
27
<---only 1 element left so we return the value back to the first subroutine that called
Then in our second subroutine we move on to the next line: result = merge(left, right) which calls the merge function to sort our left and right arrays that are just 38 and 27. The merge function sorts our two values based on which is smaller and then it adds the first one to an array although I'm not sure which array. (I need specification on this; shouldn't we have a new array every time we merge two previous arrays?) Then the merge function returns the "result" to another result variable in our merge sort function from having called the merge function. I am assuming this result is the new array that has 38 and 27 sorted in order. Then it looks like we are returning that result again to whatever called the merge sort function but I am confused because wouldn't that end everything? What about the first subroutine that paused for the left side recursion? I'm not sure what happens to:
38 27 43 3
43 3
43
and
43 3
3
Pseudo-code:
function merge_sort(m)
if length(m) ≤ 1
return m
var list left, right, result
var integer middle = length(m) / 2
for each x in m up to middle
add x to left
for each x in m after middle
add x to right
left = merge_sort(left)
right = merge_sort(right)
result = merge(left, right)
return result
Following writing merge_sort function, then it is required to merge both the left and right lists created above. There are several variants for the merge() function; one possibility is this:
function merge(left,right)
var list result
while length(left) > 0 or length(right) > 0
if length(left) > 0 and length(right) > 0
if first(left) ≤ first(right)
append first(left) to result
left = rest(left)
else
append first(right) to result
right = rest(right)
else if length(left) > 0
append first(left) to result
left = rest(left)
else if length(right) > 0
append first(right) to result
right = rest(right)
end while
return result
http://www.princeton.edu/~achaney/tmve/wiki100k/docs/Merge_sort.html
I'm not sure whether it is what you're looking for, but you can simplify your merge loop by replacing or with and in the main condition:
while length(left) > 0 and length(right) > 0
if first(left) ≤ first(right)
append first(left) to result
left = rest(left)
else
append first(right) to result
right = rest(right)
end while
# You know that one of left and right is empty
# Copy the rest of the data from the other
while length(left) > 0
append first(left) to result
left = rest(left)
end while
while length(right) > 0
append first(right) to result
right = rest(right)
end while
Yes, there are three loops, but only one of the last two is ever executed.
Working C99 code based closely on pseudo-code
Thus code uses C99 variable-length arrays (an optional feature in C11). If compiled with -DDEBUG, you'll get extensive tracing while the program is running. If compiled without, you only get the input (unsorted) and output (sorted) arrays printed. I needed it to diagnose a stupid typo (an r_pos where an l_pos was clearly required). Note the general techniques:
Document entry and exit from functions
Create a diagnostic print function (here dump_array() with one argument a 'tag' (to identify which call is being used) and the other arguments the data structure to be printed.
Call the diagnostic print function at suitable points.
Make it easy to enable or disable diagnostics.
For production quality code, my diagnostic print functions also take a FILE *fp argument and write to the given file; I cheated and used stdout here. The extra generality means the function can be used to write to stderr or a log file as well as, or instead of, stdout.
Space management
The merge_sort() code copies the complete input array into two smaller arrays (left and right) and then sorts the smaller arrays (recursion) and merges the sorted smaller arrays into the input array. This happens at each of log N levels of recursion. Some empirical testing shows that the space used is approximately 2N items — it is O(N) space usage.
Shouldn't we have a new array every time we merge two previous arrays?
In a functional programming language, you would have new arrays. In C, you use the input array as the output array too. The code copies the original input array into separate smaller arrays, sorts those smaller arrays, and merges the sorted smaller arrays into the original array.
My other question is what procedure in the code allows us to go back to before the recursion where we split the left side of our array so we can work on the right side to get 43 a 3 in order to merge them as well.
The splitting process creates a copy of the input array (so the information in the original data is temporarily superfluous). The merging process copies the (now sorted) split arrays back into the original array. (Largely repeating myself.)
Source
#include <stddef.h>
extern void merge_sort(int *array, size_t arrlen);
/* Debug */
#ifdef DEBUG
static void dump_array(const char *tag, int *array, size_t len);
static void enter_func(const char *func);
static void exit_func(const char *func);
#else
#define dump_array(t, a, l) ((void)0)
#define enter_func(f) ((void)0)
#define exit_func(f) ((void)0)
#endif
/*
function merge(left, right)
var list result
while length(left) > 0 and length(right) > 0
if first(left) ≤ first(right)
append first(left) to result
left = rest(left)
else
append first(right) to result
right = rest(right)
end while
# You know that one of left and right is empty
# Copy the rest of the data from the other
while length(left) > 0
append first(left) to result
left = rest(left)
end while
while length(right) > 0
append first(right) to result
right = rest(right)
end while
return result
end function
*/
static void merge(int *left, size_t l_len, int *right, size_t r_len, int *output)
{
size_t r_pos = 0;
size_t l_pos = 0;
size_t o_pos = 0;
enter_func(__func__);
dump_array("Left:", left, l_len);
dump_array("Right:", right, r_len);
while (r_pos < r_len && l_pos < l_len)
{
if (right[r_pos] < left[l_pos])
output[o_pos++] = right[r_pos++];
else
output[o_pos++] = left[l_pos++];
}
while (r_pos < r_len)
output[o_pos++] = right[r_pos++];
while (l_pos < l_len)
output[o_pos++] = left[l_pos++];
dump_array("Output:", output, r_len + l_len);
exit_func(__func__);
}
/*
function merge_sort(m)
if length(m) ≤ 1
return m
var list left, right, result
var integer middle = length(m) / 2
for each x in m up to middle
add x to left
for each x in m after middle
add x to right
left = merge_sort(left)
right = merge_sort(right)
result = merge(left, right)
return result
*/
void merge_sort(int *array, size_t len)
{
if (len <= 1)
return;
int left[(len+1)/2];
int l_pos = 0;
int right[(len+1)/2];
int r_pos = 0;
size_t mid = len / 2;
enter_func(__func__);
dump_array("Input:", array, len);
for (size_t i = 0; i < mid; i++)
left[l_pos++] = array[i];
for (size_t i = mid; i < len; i++)
right[r_pos++] = array[i];
dump_array("Left:", left, l_pos);
dump_array("Right:", right, r_pos);
merge_sort(left, l_pos);
merge_sort(right, r_pos);
merge(left, l_pos, right, r_pos, array);
dump_array("Result:", array, len);
exit_func(__func__);
}
/* Test code */
#include <stdio.h>
#ifdef DEBUG
static void enter_func(const char *func)
{
printf("-->> %s\n", func);
}
static void exit_func(const char *func)
{
printf("<<-- %s\n", func);
}
#endif
/* dump_array is always used */
#undef dump_array
static void dump_array(const char *tag, int *array, size_t len)
{
printf("%-8s", tag);
for (size_t i = 0; i < len; i++)
printf(" %2d", array[i]);
putchar('\n');
}
int main(void)
{
int array[] = { 38, 27, 43, 3, 9, 82, 10 };
size_t arrlen = sizeof(array) / sizeof(array[0]);
dump_array("Before:", array, arrlen);
merge_sort(array, arrlen);
dump_array("After:", array, arrlen);
return 0;
}
Sample outputs
Non-debugging
Before: 38 27 43 3 9 82 10
After: 3 9 10 27 38 43 82
Debugging
Before: 38 27 43 3 9 82 10
-->> merge_sort
Input: 38 27 43 3 9 82 10
Left: 38 27 43
Right: 3 9 82 10
-->> merge_sort
Input: 38 27 43
Left: 38
Right: 27 43
-->> merge_sort
Input: 27 43
Left: 27
Right: 43
-->> merge
Left: 27
Right: 43
Output: 27 43
<<-- merge
Result: 27 43
<<-- merge_sort
-->> merge
Left: 38
Right: 27 43
Output: 27 38 43
<<-- merge
Result: 27 38 43
<<-- merge_sort
-->> merge_sort
Input: 3 9 82 10
Left: 3 9
Right: 82 10
-->> merge_sort
Input: 3 9
Left: 3
Right: 9
-->> merge
Left: 3
Right: 9
Output: 3 9
<<-- merge
Result: 3 9
<<-- merge_sort
-->> merge_sort
Input: 82 10
Left: 82
Right: 10
-->> merge
Left: 82
Right: 10
Output: 10 82
<<-- merge
Result: 10 82
<<-- merge_sort
-->> merge
Left: 3 9
Right: 10 82
Output: 3 9 10 82
<<-- merge
Result: 3 9 10 82
<<-- merge_sort
-->> merge
Left: 27 38 43
Right: 3 9 10 82
Output: 3 9 10 27 38 43 82
<<-- merge
Result: 3 9 10 27 38 43 82
<<-- merge_sort
After: 3 9 10 27 38 43 82
I'm storing 4-card hands in a way to treat hands with different suits the same, e.g.:
9h 8h 7c 6c
is the same as
9d 8d 7h 6h
since you can replace one suit with another and have the same thing. It's easy to turn these into a unique representation using wildcards for suits. THe previous would become:
9A 8A 7B 6B
My question is - what's the most elegant way to turn the latter back into a list of the former? For example, when the input is 9A 8A 7B 6B, the output should be:
9c 8c 7d 6d
9c 8c 7h 6h
9c 8c 7s 6s
9h 8h 7d 6d
9h 8h 7c 6c
9h 8h 7s 6s
9d 8d 7c 6c
9d 8d 7h 6h
9d 8d 7s 6s
9s 8s 7d 6d
9s 8s 7h 6h
9s 8s 7c 6c
I have some ugly code that does this on a case-by-case basis depending on how many unique suits there are. It won't scale to hands with more cards. Also in a situation like:
7A 7B 8A 8B
it will have duplicates, since in this case A=c and B=d is the same as A=d and B=c.
What's an elegant way to solve this problem efficiently? I'm coding in C, but I can convert higher-level code down to C.
There are only 4 suits so the space of possible substitutions is really small - 4! = 24 cases.
In this case, I don't think it is worth it, to try to come up with something especially clever.
Just parse the string like "7A 7B 8A 8B", count the number of different letters in it, and based on that number, generate substitutions based on a precomputed set of substitutions.
1 letter -> 4 possible substitutions c, d, h, or s
2 letters -> 12 substitutions like in Your example.
3 or 4 letters -> 24 substitutions.
Then sort the set of substitutions and remove duplicates. You have do sort the tokens in every string like "7c 8d 9d 9s" and then sort an array of the strings to detect duplicates but that shouldn't be a problem. It's good to have the patterns like "7A 7B 8A 8B" sorted too (the tokens like: "7A", "8B" are in an ascending order).
EDIT:
An alternative for sorting might be, to detect identical sets if ranks associated with two or more suits and take it into account when generating substitutions, but it's more complicated I think. You would have to create a set of ranks for each letter appearing in the pattern string.
For example, for the string "7A 7B 8A 8B", with the letter A, associated is the set {7, 8} and the same set is associated with the letter B. Then You have to look for identical sets associated with different letters. In most cases those sets will have just one element, but they might have two as in the example above. Letters associated with the same set are interchangeable. You can have following situations
1 letter no duplicates -> 4 possible substitutions c, d, h, or s
2 letters no duplicates -> 12 substitutions.
2 letters, 2 letters interchangeable (identical sets for both letters) -> 6 substitutions.
3 letters no duplicates -> 24 substitutions.
3 letters, 2 letters interchangeable -> 12 substitutions.
4 letters no duplicates -> 24 substitutions.
4 letters, 2 letters interchangeable -> 12 substitutions.
4 letters, 3 letters interchangeable -> 4 substitutions.
4 letters, 2 pairs of interchangeable letters -> 6 substitutions.
4 letters, 4 letters interchangeable -> 1 substitution.
I think a generic permutation function that takes an array arr and an integer n and returns all possible permutations of n elements in that array would be useful here.
Find how how many unique suits exist in the hand. Then generate all possible permutations with those many elements from the actual suits [c, d, h, s]. Finally go through each permutation of suits, and assign each unknown letter [A, B, C, D] in the hand to the permuted values.
The following code in Ruby takes a given hand and generates all suit permutations. The heaviest work is being done by the Array.permutation(n) method here which should simplify things a lot for a corresponding C program as well.
# all 4 suits needed for generating permutations
suits = ["c", "d", "h", "s"]
# current hand
hand = "9A 8A 7B 6B"
# find number of unique suits in the hand. In this case it's 2 => [A, B]
unique_suits_in_hand = hand.scan(/.(.)\s?/).uniq.length
# generate all possible permutations of 2 suits, and for each permutation
# do letter assignments in the original hand
# tr is a translation function which maps corresponding letters in both strings.
# it doesn't matter which unknowns are used (A, B, C, D) since they
# will be replaced consistently.
# After suit assignments are done, we split the cards in hand, and sort them.
possible_hands = suits.permutation(unique_suits_in_hand).map do |perm|
hand.tr("ABCD", perm.join ).split(' ').sort
end
# Remove all duplicates
p possible_hands.uniq
The above code outputs
9c 8c 7d 6d
9c 8c 7h 6h
9c 8c 7s 6s
9d 8d 7c 6c
9d 8d 7h 6h
9d 8d 7s 6s
9h 8h 7c 6c
9h 8h 7d 6d
9h 8h 7s 6s
9s 8s 7c 6c
9s 8s 7d 6d
9s 8s 7h 6h
Represent suits as sparse arrays or lists, numbers as indexes, hands as associative arrays
In your example
H [A[07080000] B[07080000] C[00000000] D[00000000] ] (place for four cards)
To get the "real" hands always apply the 24 permutations (fixed time), so you don't have to care about how many cards has your hand A,B,C,D -> c,d,h,s with the following "trick"> store always in alphabetical order>
H1 [c[xxxxxx] d[xxxxxx] s[xxxxxx] h[xxxxxx]]
Since Hands are associative arrays, duplicated permutations does not generate two different output hands.
#include <stdio.h>
#include <stdlib.h>
const int RANK = 0;
const int SUIT = 1;
const int NUM_SUITS = 4;
const char STANDARD_SUITS[] = "dchs";
int usedSuits[] = {0, 0, 0, 0};
const char MOCK_SUITS[] = "ABCD";
const char BAD_SUIT = '*';
char pullSuit (int i) {
if (usedSuits [i] > 0) {
return BAD_SUIT;
}
++usedSuits [i];
return STANDARD_SUITS [i];
}
void unpullSuit (int i) {
--usedSuits [i];
}
int indexOfSuit (char suit, const char suits[]) {
int i;
for (i = 0; i < NUM_SUITS; ++i) {
if (suit == suits [i]) {
return i;
}
}
return -1;
}
int legitimateSuits (const char suits[]) {
return indexOfSuit (BAD_SUIT, suits) == -1;
}
int distinctSuits (const char suits[]) {
int i, j;
for (i = 0; i < NUM_SUITS; ++i) {
for (j = 0; j < NUM_SUITS; ++j) {
if (i != j && suits [i] == suits [j]) {
return 0;
}
}
}
return 1;
}
void printCards (char* mockCards[], int numMockCards, const char realizedSuits[]) {
int i;
for (i = 0; i < numMockCards; ++i) {
char* mockCard = mockCards [i];
char rank = mockCard [RANK];
char mockSuit = mockCard [SUIT];
int idx = indexOfSuit (mockSuit, MOCK_SUITS);
char realizedSuit = realizedSuits [idx];
printf ("%c%c ", rank, realizedSuit);
}
printf ("\n");
}
/*
* Example usage:
* char** mockCards = {"9A", "8A", "7B", "6B"};
* expand (mockCards, 4);
*/
void expand (char* mockCards[], int numMockCards) {
int i, j, k, l;
for (i = 0; i < NUM_SUITS; ++i) {
char a = pullSuit (i);
for (j = 0; j < NUM_SUITS; ++j) {
char b = pullSuit (j);
for (k = 0; k < NUM_SUITS; ++k) {
char c = pullSuit (k);
for (l = 0; l < NUM_SUITS; ++l) {
char d = pullSuit (l);
char realizedSuits[] = {a, b, c, d};
int legitimate = legitimateSuits (realizedSuits);
if (legitimate) {
int distinct = distinctSuits (realizedSuits);
if (distinct) {
printCards (mockCards, numMockCards, realizedSuits);
}
}
unpullSuit (l);
}
unpullSuit (k);
}
unpullSuit (j);
}
unpullSuit (i);
}
}
int main () {
char* mockCards[] = {"9A", "8A", "7B", "6B"};
expand (mockCards, 4);
return 0;
}
I feel that it should be something very simple and obvious but just stuck on this for the last half an hour and can't move on.
All I need is to split an array of elements into N groups based on element index.
For example we have an array of 30 elements [e1,e2,...e30], that has to be divided into N=3 groups like this:
group1: [e1, ..., e10]
group2: [e11, ..., e20]
group3: [e21, ..., e30]
I came up with nasty mess like this for N=3 (pseudo language, I left multiplication on 0 and 1 just for clarification):
for(i=0;i<array_size;i++) {
if(i>=0*(array_size/3) && i<1*(array_size/3) {
print "group1";
} else if(i>=1*(array_size/3) && i<2*(array_size/3) {
print "group2";
} else if(i>=2*(array_size/3) && i<3*(array_size/3)
print "group3";
}
}
But what would be the proper general solution?
Thanks.
What about something like this?
for(i=0;i<array_size;i++) {
print "group" + (Math.floor(i/(array_size/N)) + 1)
}
Here's a little function which will do what you want - it presumes you know the number of groups you want to make:
function arrayToGroups(source, groups) {
//This is the array of groups to return:
var grouped = [];
//work out the size of the group
var groupSize = Math.ceil(source.length/groups);
//clone the source array so we can safely splice it (splicing modifies the array)
var queue = source.slice(0);
for (var r=0;r<groups;r++) {
//Grab the next groupful from the queue, and append it to the array of groups
grouped.push(queue.splice(0, groupSize));
}
return grouped;
}
And you use it like:
var herbs = ['basil', 'marjoram', 'aniseed', 'parsely', 'chives', 'sage', 'fennel', 'oregano', 'thyme', 'tarragon', 'rosemary'];
var herbGroups = arrayToGroups(herbs, 3);
which returns:
herbGroups[0] = ['basil', 'marjoram', 'aniseed', 'parsely']
herbGroups[1] = ['chives', 'sage', 'fennel', 'oregano']
herbGroups[2] = ['thyme', 'tarragon', 'rosemary']
It doesn't do any sanity checking to make sure you pass in an array and a number, but you could add that easily enough. You could probably prototype it into the Javascript's object type, too, which would give you a handy 'toGroups' method on Arrays.
Using a vector language makes this task simple, right tool and all that. Just thought I'd throw this out there to let folks check out an alternative methodology.
The explained version in K (an APL descendent):
split:{[values;n] / define function split with two parameters
enum:!n / ! does enumerate from 0 through n exclusive, : is assign
floor:_(#values)%n / 33 for this sample, % is divide, _ floor, # count
cut:floor*enum / 0 33 66 for this sample data, * multiplies atom * vector
:cut _ values / cut the values at the given cutpoints, yielding #cut lists
}
values:1+!30 / generate values 1 through 30
n:3 / how many groups to split into
groups:split[values;n] / set the groups
yields the expected output:
(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 28 29 30)
The short version in K :
split:{((_(#x)%y)*!y)_ x}
groups:split[1+!30;3]
yields the same output:
(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 28 29 30)
I modified Beejamin's function above and just wanted to share it.
function arrayToGroups($source, $pergroup) {
$grouped = array();
$groupCount = ceil(count($source)/$pergroup);
$queue = $source;
for ($r=0; $r<$groupCount; $r++) {
array_push($grouped, array_splice($queue, 0, $pergroup));
}
return $grouped;
}
This asks how many items to have per group instead of how many groups total. PHP.
const int g = 3; // number of groups
const int n = (array_size + g - 1)/g; // elements per group
for (i=0,j=1; i<array_size; ++i) {
if (i > j*n)
++j;
printf("Group %d\n", j);
}
int group[3][10];
int groupIndex = 0;
int itemIndex = 0;
for(i = 0; i < array_size; i++)
{
group[groupIndex][itemIndex] = big_array[i];
itemIndex++;
if (itemIndex == 10)
{
itemIndex = 0;
groupIndex++;
}
}
There's probably an infinite number of ways of do this.
I'd suggest: for each group, create a base pointer and count.
struct group {foo * ptr; size_t count };
group * pgroups = new group [ngroups];
size_t objects_per_group = array_size / ngroups;
for (unsigned u = 0; u < ngroups; ++u ) {
group & g = pgroups[u];
size_t index = u * objects_per_group;
g.ptr = & array [index];
g.count = min (objects_per_group, array_size - index); // last group may have less!
}
...`
for (unsigned u = 0; u < ngroups; ++u) {
// group "g" is an array at pgroups[g].ptr, dimension pgroups[g].count
group & g = pgroups[u];
// enumerate the group:
for (unsigned v = 0; v < g.count; ++v) {
fprintf (stdout, "group %u, item %u, %s\n",
(unsigned) u, (unsigned) v, (const char *) g.ptr[v]->somestring);
} }
delete[] pgroups;
I think the problem is a little more complicated; and considering that your only look at group as a 1 dimensional problem your going to get a very odd view of what groups actually are.
Firstly the problem is dimensional according to the number of group primes, and group combinations you are dealing with. In Mathematics; this is represented as n to the power of n or n^n which can be translated to !n (factor of n).
If I have 5 groups arrayed as (1, 2, 3, 4, 5) then I wanted to represent it as certain groups or combonations of groups according to a factorial expression then the combonations get bigger
Group 1x1 = 1,2,3,4,5
Group 2x1 = 12, 23, 45, 13, 14, 15, 21, 24, 25, 31, 32, 34, 35, 41, 42, 43, 45, 51, 52, 53, 54
so the strategy creates a branch systematic branch (easy enough)
12, 13, 14, 15
21, 22, 23, 24
31, 32, 34, 35
41, 42, 43, 45
51, 52, 53, 55
Group 1 + 2x2x1 = (1, 23, 45), (2, 13, 45), (3, 12, 45), (4, 12, 35), (1, 24, 35), (1, 25, 35), (1, 32, 45), (1, 34, 25), (1, 35, 24), ... etc
As you can see when you begin to add factorial sets the comboniations become not so easy to create a mathematic reference to express the terms. It gets worst when you get up into a base set > 3 or 4 length.
If I am understanding your question: you want to expressing in a generic terms an algorythm which allows you to create grouping strategies programmatically?
This is a complicated set; and is represented best in calculus; as set theory. Otherwise all your doing is a two dimensional array handling.
the first Array expresses the grouping strategy;
the second Array expresses the grouping elements.
I don't think this is what your being asked to do, because the term "GROUP" in mathematics has a very specific allocation for the term. You should not use the term group; rather express it as a set; set1, set2 if that is what you are doing.
Set1 contains elements of set2; and therefor this is handled with the same mathematics as Sets and unions are expressed. Lookup "Vin Diagrams" and "Union"; avoid using the term group unless you are representing the factor of a set.
http://en.wikipedia.org/wiki/Group_(mathematics)
I think what you are trying to express is the groups within a known set or table; This is on the wikipedia.org example D2.
In which case that means you have to look at the problem like a rubik's cube; and it gets complicated.
I'm working the same problem in javascript; when I am done I might publish it ;). It's very complicated.