Algorithm to check if a multidimensional array contains another? - arrays

Say I have two multidimensional arrays of equal depth, say:
[ [1, 2, 3],
[4, 5, 6],
[7, 8, 9] ]
and
[ [2, 3],
[5, 6] ]
What sort of algorithm can I follow to determine if the latter is a contiguous subarray of the former?
For example, with the above example, it is:
And also with this pair of 3d arrays:
[ [ [4, 6],
[5, 7] ],
[ [2, 8],
[9, 3] ] ]
[ [ [4, 6] ],
[ [2, 8] ] ]
Another way of interpreting this is that by removing the first or last item from a dimension of the first array repeatedly, you will eventually get the target array.

The Rabin-Karp string search algorithm can be extended to multiple dimensions to solve this problem.
Lets say your pattern array is M rows by N columns:
Using any rolling hash function, like a polynomial hash, first replace every column of your pattern array with the hash of the column, reducing it to 1 dimension. Then hash the remaining row. This will be your pattern hash.
Now use the rolling hash in your target array to replace all values in rows >= M by the hash of those values with the M-1 values above them.
Then, similarly replace all remaining values in columns >= N-1 with the hash of those values and the N-1 values to the left.
Finally, find any instances of the pattern hash in the resulting matrix. When you find one, compare with your pattern array to see if it's a real match.
This algorithm extends to as many dimensions as you like and, like simple Rabin-Karp, it takes O(N) expected time if the number of dimensions is constant.

The simple and naive approach would be, to look for first (0,0) match and then to compare the sub array.
Example: (Python)
hay=[ [1, 2, 3],
[4, 5, 6],
[7, 8, 9] ]
needle=[ [2, 3],
[5, 6] ]
def get_sub_array(array,i,j,width,height):
sub_array=[]
for n in range(i,i+height):
sub_array.append(array[n][j:j+width])
return sub_array
def compare(arr1,arr2):
for i in range(len(arr1)):
for j in range(len(arr1[0])):
if arr1[i][j]!=arr2[i][j]:
return False
return True
def is_sub_array(hay,needle):
hay_width=len(hay[0])
hay_height=len(hay)
needle_width=len(needle[0])
needle_height=len(needle)
for i in range(hay_height-needle_height+1):
for j in range(hay_width-needle_width+1):
if hay[i][j]==needle[0][0]:
if compare(
get_sub_array(hay,i,j,needle_width,needle_height),
needle
):
return True
return False
print(is_sub_array(hay,needle))
Output:
True

Related

Can someone explain in detail how mapping this array works step by step

The original array: [ [3, 5], [9, 6], [3,1] ]
1) Make the first number in each mini array the smaller number and the second number in each mini array the bigger number
- [ [3, 5], [9, 6], [3,1] ] -> [[ 3,5], [6,9], [1,3]]
2) Sort the mini arrays by first number.
- [ [3,5], [6,9], [1,3] ] -> [ [1,3], [3,5], [6,9] ]
So [ [3, 5], [9, 6], [3,1] ] -> [ [1,3], [3,5], [6,9] ] by the end of the sorting transformation.
Can someone explain in a step by step, detailed, clear, concise way how to use array.map() to make this happen?
Use map to make the nested array numbers placed in increasing order, then apply sort based on first number in the nested array.
const arr = [
[3, 5],
[9, 6],
[3, 1]
];
const sortedArr = arr
.map(([num1, num2]) => num2 < num1 ? [num2, num1] : [num1, num2])
.sort(([arr1num1], [arr2num1]) => arr1num1 - arr2num1);
console.log(sortedArr);
-- Edit--
Result of map
[[3, 5], [6, 9], [1, 3]];
In the sort function, I'am doing array destructuring (see - https://javascript.info/destructuring-assignment). Basically, I'am only extracting the first element from array and storing in separate variable. In our case, arr1num1 and arr2num1.
Example-
const arr = [3, 5];
// Extracting the first element from array and saving in variable - arr1num1.
// I do not need second array element 5, so i did not extracted the second array element
const [arr1num1] = arr; // arr1num1 will have now value 3
console.log(arr1num1);
// If second array element is also required, then the above statement will become const [num1, num2] = arr; where num1 -> 3 and num2 ->5
Alternative, to above would be to directly access array elements using there index.
const arr = [
[3, 5],
[9, 6],
[3, 1]
];
const sortedArr = arr
.map(([num1, num2]) => num2 < num1 ? [num2, num1] : [num1, num2])
.sort((arr1, arr2) => arr1[0] - arr2[0]);
console.log(sortedArr);
To know more about sort, see - Sorting
How sorting works,
In first iteration, swapping of [3, 5] & [6, 9] will happen based on sort condition.
arr1num1 -> 3
arr2num1 -> 6
The statement arr1num1 - arr2num1 will check if 3 is greater than 6. If yes, it will swap the arrays [3, 5] and [6, 9]. Since, 3 is not greater than 9, so no swapping will take place.
Second Iteration, swapping of [6, 9] and [1, 3] will take place based on condition.
arr1num1 -> 6
arr1num2 -> 1
Since, 6 > than 1, swapping will take place.
Before Swapping array will be- `[[3, 5], [6, 9], [1, 3]]`;
After Swapping array will be - `[[3, 5], [1, 3], [6, 9]]`;
This process will continue, until your array gets sorted.

Algorithm Logic, Splitting Arrays

I'm not looking for a solution just pseudo code or logic that would help me derive an answer.
Given an array:
[1,2,3,4]
I want to split this into two arrays of varying lengths and contents whose sum lengths are equal to the length of the given array. It would be ideal without repetition.
Example output:
[[1],[2, 3, 4]]
[[1, 2], [3, 4]]
[[1, 3], [2, 4]]
[[1, 4],[2, 3]]
[[1, 2, 3], [4]]
[[2], [1, 3, 4]]
[[2, 4], [1, 3]]
[[3], [1, 2, 4]]
More example:
[[1, 3, 4, 6, 8], [2, 5, 7]] //this is a possible combination of 1 through 8
//array
Intuitions:
First attempt involved pushing the starting number array[i] to the result array[0], the second loop moving the index for the third loop to start iterating as is grabbed sublists. Then fill the other list with remaining indices. Was poorly conceived...
Second idea is permutations. Write an algorithm that reorganizes the array into every possible combination. Then, perform the same split operation on those lists at different indexes keeping track of unique lists as strings in a dictionary.
[1,2,3,4,5,6,7,8]
^
split
[1,2,3,4,5,6,7,8]
^
split
[1,3,4,5,6,7,8,2]
^
split
I'm confident that this will produce the lists i'm looking for. However! i'm afraid it may be less efficient than I'd like due to the need for sorting when checking for duplicates and permutations is expensive in the first place.
Please respond with how you would approach this problem, and why.
Pseudocode. The idea is to start with an item in one of the bags, and then to place the next item once in the same bag, once in the other.
function f(A):
// Recursive function to collect arrangements
function g(l, r, i):
// Base case: no more items
if i == length(A):
return [[l, r]]
// Place the item in the left bag
return g(l with A[i], r, i + 1)
// Also return a version where the item
// is placed in the right bag
concatenated with g(l, r with A[i], i + 1)
// Check that we have at least one item
if A is empty:
return []
// Start the recursion with one item placed
return g([A[0]], [], 1)
(PS see revisions for JavaScript code.)

Can anyone show me an algorithm to create a function that returns all possible partitions of an array into n subsets while maintaining order of array?

The function would basically just generate all of the ways to partition an array into n buckets while keeping the order of the original array. It would generate an array of arrays of arrays
Function signature:
func(arr, n)
arr = an array of numbers
n = int <= length(arr)
Example function calls:
func([1, 2, 3], 1) would return [ [[1, 2, 3]] ]
func([1, 2, 3], 2) would return [ [[1],[2, 3]], [[1, 2],[3]]]
func([1, 2, 3], 3) would return [ [[1], [2], [3]] ]
I was able to figure this out.
I did it by
1. implementing algorithm in this post - How to find all partitions of a set
2. filter out partitions with elements that do not maintain the order of the original array
3. filter out partitions that are not of size n

Sort array based on frequency

How can I sort an array by most repetitive values.?
suppose I have an array [3, 3, 3, 3, 4, 4]
Expected the result as [3, 4] since 3 is most repeated and 4 is least repeated.
Is there any way too do it?
Thanks in advance....!
Here is one way of doing it:
distictList: Get all distinct values from the array and store in this
countArray: For each ith index in distinctList countArray[i] holds the occurrence of the distinctList[i]
Now sort countArray and apply same swaps on the distinctList simultaneously.
Ex: [3, 3, 4, 4, 4]
distinctList [3,4]
countArray [2,3]
Descending sort countArray [3,2] sorting distinctList at the same time [4,3]
Output: [4, 3]`
Simple in Python:
data = [3, 2, 3, 4, 2, 1, 3]
frequencies = {x:0 for x in data}
for x in data:
frequencies[x] = frequencies[x] + 1
sorted_with_repetitions = sorted(data, key=lambda x:frequencies[x],reverse=True)
sorted_without_repetitions = sorted(frequencies.keys(), key=lambda x:frequencies[x],reverse=True)
print(data)
print(sorted_with_repetitions)
print(sorted_without_repetitions)
print(frequencies)
The same approach (an associative container to collect distinct values and count occurrences, used in a custom comparison to sort an array with the original data or only distinct items) is suitable for Java.

numpy using multidimensional index array on another multidimensional array

I have a 2 multidimensional arrays, and I'd like to use one as the index to produce a new multidimensional array. For example:
a = array([[4, 3, 2, 5],
[7, 8, 6, 8],
[3, 1, 5, 6]])
b = array([[0,2],[1,1],[3,1]])
I want to use the first array in b to return those indexed elements in the first array of a, and so on. So I want the output to be:
array([[4,2],[8,8],[6,1]])
This is probably simple but I couldn't find an answer by searching. Thanks.
This is a little tricky, but the following will do it:
>>> a[np.arange(3)[:, np.newaxis], b]
array([[4, 2],
[8, 8],
[6, 1]])
You need to index both the rows and the columns of the a array, so to match your b array you would need an array like this:
rows = np.array([[0, 0],
[1, 1],
[2, 2]])
And then a[rows, b] would clearly return what you are after. You can get the same result relying on broadcasting as above, replacing the rows array with np.arange(3)[:, np.newaxis], which is equivalent to np.arange(3).reshape(3, 1).

Resources