Big for loop for permutation - arrays

I receive 3 integers, "x", "y" and "z". Then a last integer which is "n".
I have to find all possible combinations between x, y and z as in a permutation, but I only need to save those ones where the sum of all values is not equal to n (x + y + z != n).
I have done this trough a big for loop. As you can see, the print output confirms that this logic works, so all the possible combinations are found with any 3 integers you use. Each combination is temporary saved on a list which is constantly overwritten.
I filter the combinations so you can see with the print function only those which sum of the values on the list is not n. However, when I want to save each combination found, it just saves repeated values and it seems that the append method is not working as I need to.
# Example:
#
# Input: x = 1
# y = 1
# z = 1
# n = 2
#
# Output = [[0,0,0],[0,0,1],[0,1,0],[1,0,0],[1,1,1]]
x = int(input())
y = int(input())
z = int(input())
n = int(input())
list_x = [x for x in range(x+1)] #numbers from 0 to x
list_y = [y for y in range(y+1)] #numbers from 0 to y
list_z = [z for z in range(z+1)] #numbers from 0 to z
results = []
#Big for loop which makes the permutation
combination = [0,0,0]
for num_x in list_x:
combination[0] = num_x
for num_y in list_y:
combination[1] = num_y
for num_z in list_z:
combination[2]=num_z
if sum(combination) != n: #Find combinations where total sum != to n
print(combination) #print the combination found
results.append(combination) #save the combination in a list of lists
print(results) #print the lists of lists
Any kind of help is really appreciated. Thank you.

It's because combination is a reference to an underlying list, and that's what you're storing in the results (the reference, not the list). This is one of those "a-ha" moments that all Python coders experience, when they start to fully grok the language :-)
Every time you change an element of the list (as opposed to the actual list), every reference to it seems to change as well, because there's only one list.
This makes it appear that you're changing things that have already been set at an earlier time but that's not actually the case.
You can see that in action with:
>>> xyzzy = [1, 2, 3] # The list.
>>> plugh = xyzzy # Copies reference, not list content.
>>> xyzzy[1] = 99 # Changes list content (for BOTH references).
>>> xyzzy ; plugh # Result: they are both changed.
[1, 99, 3]
[1, 99, 3]
>>> xyzzy = [4, 5, 6] # Makes xyzzy reference point to NEW list.
>>> xyzzy ; plugh # Result: they are different.
[4, 5, 6]
[1, 99, 3]
To fix that, you can just get rid of combination and just use something like:
for num_x in list_x:
for num_y in list_y:
for num_z in list_z:
if num_x + num_y + num_z != n:
results.append([num_x, num_y, num_z])
print(results[-1])
That creates and appends a new list each time, so changes won't seem to travel back through time.
And, for what it's worth, this can also be done with a more Pythonic list comprehension. Using your supplied test data, dummied up:
list_x, list_y, list_z, n = [0, 1], [0, 1], [0, 1], 2
result = [[x, y, z] \
for x in list_x \
for y in list_y \
for z in list_z \
if x + y + z != n]
print(result)
I've split the comprehension across multiple lines for readability but it could just as easily go on one line, and it gives the expected output as per below:
[[0, 0, 0], [0, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1]]

Related

sets of numpy 2D array rows having unique values in each row position

Consider array a, holding some of the permutations of 1,2,3,4. (my actual arrays may be larger)
import numpy as np
n = 3
a = np.array([[1, 2, 3, 4],
[1, 2, 4, 3],
[1, 3, 4, 2],
[1, 4, 3, 2],
[2, 3, 4, 1],
[2, 4, 3, 1],
[3, 1, 4, 2],
[4, 1, 2, 3]]))
I want to identify sets of n rows (in this example, n=3) where each row position holds unique values.
In this example, the output would be:
out = [[0, 4, 7],
[2, 5, 7],
[3, 4, 7]]
The 1st row of out indicates that a[0], a[4], and a[7] have unique values in each row position
When n = 2, there are 11 row pairs that match the criteria: [[0,4], [0,6], [0,7], [1,5] ...etc
When n = 4, there are 0 rows that match the criteria.
I'm new enough to python that I can't find a good way to approach this situation.
Solving this problem efficiently is far from not easy. Indeed, the brute-force solution consisting is using n nested loop is very inefficient: its complexity is O(c r! / (r-n)!) where r is the number of rows of a and c is the number of columns of a (note that ! is the factorial). Since r is a number of permutation which already grow experientially with the number of unique items in a, this means the complexity of this solution is really bad.
A more efficient solution (but still not great) is to pick a row, filter the other rows that can match with it (ie. there is no items at the same position that are equal), and then recursively do the same thing n times (the picked row are only the one that are filtered). The several sets of row indices can be appended in a list during the recursion. It is hard to evaluate the complexity of this solution, but it is far much faster in practice since most rows hopefully does not match together and the filtered rows tends to decrease exponentially too. That being said, the complexity is certainly still exponential since the size of the output appears to grow exponentially too and the output needs to be written.
Here is the implementation:
def recursiveFindSets(a, i, n, availableRows, rowIndices, results):
if availableRows.size == 0:
return
for k in availableRows:
# Save the current choice
rowIndices[i] = k
# The next selected rows needs to be bigger than `k` so to prevent replicates
newAvailableRows = availableRows[availableRows > k]
# If there is no solutions with a[k], then choose another
if newAvailableRows.size == 0:
continue
# Find rows that contains different items of a[i]
goodMatches = np.all(a[newAvailableRows] != a[k], axis=1)
# Find the location relative to `a` and not `a[availableRows]`
newAvailableRows = newAvailableRows[goodMatches]
# If there is no solutions with a[k], then choose another
if newAvailableRows.size == 0:
continue
if i == n-2:
# Generate some solutions from `newAvailableRows`
for k2 in newAvailableRows:
rowIndices[i+1] = k2
results.append(rowIndices.copy())
elif i < n-2:
recursiveFindSets(a, i+1, n, newAvailableRows, rowIndices, results)
def findSets(a, n):
availableRows = np.arange(a.shape[0], dtype=int) # Filter
rowIndices = np.empty(n, dtype=np.int_) # Current set of row indices
results = [] # List of all the sets
recursiveFindSets(a, 0, n, availableRows, rowIndices, results)
if len(results) == 0:
return np.empty((0, n), dtype=int)
return np.vstack(results)
findSets(a, 3)
# Output:
# array([[0, 4, 7],
# [2, 5, 7],
# [3, 4, 7]])
You can reduce this problem to finding all cliques of size n in an undirected graph. Nodes in the graph are given by row indices of a. There is an edge between i and j if (a[i] != a[j]).all().
Here is one implementation based on networkx. A function enumerate_all_cliques(g) iterates over cliques in g in order of increasing size. We discard all cliques of size less than n, keep those of size n, and stop once the first clique of size greater than n is found or cliques run out.
from itertools import combinations
import networkx as nx
def f(arr, n):
nodes = np.arange(arr.shape[0])
g = nx.Graph()
g.add_nodes_from(nodes)
for i, j in combinations(nodes, 2):
if (arr[i] != arr[j]).all():
g.add_edge(i, j)
for c in nx.algorithms.clique.enumerate_all_cliques(g):
lc = len(c)
if lc == n:
yield c
elif lc > n:
break
print(list(f(a, 3)))
# [[0, 4, 7], [2, 5, 7], [3, 4, 7]]
Here is another approach: find all maximal cliques and yield all subsets of size n from each clique. This can lead to double-counting, hence set is used before the return statement.
def f(arr, n):
nodes = np.arange(arr.shape[0])
g = nx.Graph()
g.add_nodes_from(nodes)
for i, j in combinations(nodes, 2):
if (arr[i] != arr[j]).all():
g.add_edge(i, j)
cliques = set()
# iterate over maximal cliques
for c in nx.algorithms.clique.find_cliques(g):
# update the clique set subsets of c
cliques.update(map(frozenset, combinations(c, n)))
# return all cliques of size n without doublecounting
return [list(c) for c in cliques]
print(f(a, 3))
# [[2, 5, 7], [3, 4, 7], [0, 4, 7]]
The performance of either approach will vary depending on input values.

circularArrayRotation algorithm ruby

I am using hacker rank and I do not understand why my ruby code only works for one test case out of like 20. Here is the question:
John Watson knows of an operation called a right circular rotation on
an array of integers. One rotation operation moves the last array
element to the first position and shifts all remaining elements right
one. To test Sherlock's abilities, Watson provides Sherlock with an
array of integers. Sherlock is to perform the rotation operation a
number of times then determine the value of the element at a given
position.
For each array, perform a number of right circular rotations and
return the values of the elements at the given indices.
Function Description
Complete the circularArrayRotation function in the editor below.
circularArrayRotation has the following parameter(s):
int a[n]: the array to rotate
int k: the rotation count
int queries[1]: the indices to report
Returns
int[q]: the values in the rotated a as requested in m
Input Format
The first line contains 3 space-separated integers, n, k, and q, the number of elements in the integer array, the rotation count and the number of queries. The second line contains n space-separated integers,
where each integer i describes array element a[i] (where 0 <= i < n). Each of the q subsequent lines contains a single integer, queries[i], an index of an element
in a to return.
Constraints
Sample Input 0
3 2 3
1 2 3
0
1
2
Sample Output 0
2
3
1
Here is my code :
def circularArrayRotation(a, k, queries)
q = []
while k >= 1
m = a.pop()
a.unshift m
k = k - 1
end
for i in queries do
v = a[queries[i]]
q.push v
end
return q
end
It only works for the sample text case but I can't figure out why. Thanks for any help you can provide.
Haven't ran any benchmarks, but this seems like a job for the aptly named Array.rotate() method:
def index_at_rotation (array, num_rotations, queries)
array = array.rotate(-num_rotations)
queries.map {|q| array[q]}
end
a = [1, 2, 3]
k = 2
q = [0,1, 2]
index_at_rotation(a, k, q)
#=> [2, 3, 1]
Handles negative rotation values and nil results as well:
a = [1, 6, 9, 11]
k = -1
q = (1..4).to_a
index_at_rotation(a, k, q)
#=> [9, 11, 1, nil]
I don't see any errors in your code, but I would like to suggest a more efficient way of making the calculation.
First observe that after q rotations the element at index i will at index (i+q) % n.
For example, suppose
n = 3
a = [1,2,3]
q = 5
Then after q rotations the array will be as follows.
arr = Array.new(3)
arr[(0+5) % 3] = a[0] #=> arr[2] = 1
arr[(1+5) % 3] = a[1] #=> arr[0] = 2
arr[(2+5) % 3] = a[2] #=> arr[1] = 3
arr #=> [2,3,1]
We therefore can write
def doit(n,a,q,queries)
n.times.with_object(Array.new(n)) do |i,arr|
arr[(i+q) % n] = a[i]
end.values_at(*queries)
end
doit(3,[1,2,3],5,[0,1,2])
#=> [2,3,1]
doit(3,[1,2,3],5,[2,1])
#=> [1, 3]
doit(3,[1,2,3],2,[0,1,2])
#=> [2, 3, 1]
p doit(3,[1,2,3],0,[0,1,2])
#=> [1,2,3]
doit(20,(0..19).to_a,25,(0..19).to_a.reverse)
#=> [14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
# 4, 3, 2, 1, 0, 19, 18, 17, 16, 15]
Alternatively, we may observe that after q rotations the element at index j was initially at index (j-q) % n.
For the earlier example, after q rotations the array will be
[a[(0-5) % 3], a[(1-5) % 3], a[(2-5) % 3]]
#=> [a[1], a[2], a[0]]
#=> [2,3,1]
We therefore could instead write
def doit(n,a,q,queries)
n.times.map { |j| a[(j-q) % n] }.values_at(*queries)
end

Randomly picking unique elements

I use rand to reach random three element from a and add this m values to array but I want them to be unique. So, array can't be like this: array = [1,1,2]. How can I check when two elements are equal and how to prevent this other than sample method? I was thinking about this: Let's assume m=1 when times method runs the first time. If m =1 at the second time, I want to skip this value and reach a different one. Is there any code explanation for this ? Or maybe more different way?
a = [1, 2, 3, 4]
array = []
3.times do
m = a[rand(a.size)]
array << m
end
Use shuffle and slice 3 elements:
a = [1, 2, 3, 4]
shuffled = a.shuffle[0..2]
As I understand you wish to write a method similar to Array#sample, that returns a pseudo-random sample of a given size without replacement. I suggest the following, which I believe would be relatively efficient, particularly when the sample size is small or large relative to the size of array.
def sample(arr, sample_size)
n = arr.size
raise ArgumentError if n < sample_size
a = arr.dup
m = (sample_size < n/2) ? sample_size : n - sample_size
m.times do
i = rand(n)
n -= 1
a[i], a[n] = a[n], a[i]
end
n = arr.size
(sample_size < n/2) ? a[n-sample_size..] : a[0, sample_size]
end
a = [7, 5, 7, 1, 9, 6, 2, 0, 6, 7]
Notice that if sample_size >= arr.size/2 I sample arr.size - sample_size elements and return the unsampled elements.

Numpy: Comparing array elements within another array

I have a numpy array
X = [[1,2], [3,4], [5,6], [1,2], [5,6]]
I want a numpy array Y = [1, 2, 3, 1, 3], where [1,2] is replaced by 1, [3,4] replaced by 2 and so on. This is for a very large (think millions) X.
Intuition is Y[X == [1,2]] = 1. But this does't work.
Intuition is Y[X == [1,2]] = 1. But this does't work.
Here is how to make it work:
Y = np.empty(len(X), dtype=np.int)
Y[np.all(X == [1, 2], 1)] = 1
To process all the possible values:
s = set(map(tuple, X))
r = np.arange(1, len(s) + 1) # or assign whatever values you want
cond = [np.all(X == v, 1) for v in s]
Y = np.dot(r, cond)

Array sorting using presorted ranking

I'm building a decision tree algorithm. The sorting is very expensive in this algorithm because for every split I need to sort each column. So at the beginning - even before tree construction I'm presorting variables - I'm creating a matrix so for each column in the matrix I save its ranking. Then when I want to sort the variable in some split I don't actually sort it but use the presorted ranking array. The problem is that I don't know how to do it in a space efficient manner.
A naive solution of this is below. This is only for 1 variabe (v) and 1 split (split_ind).
import numpy as np
v = np.array([60,70,50,10,20,0,90,80,30,40])
sortperm = v.argsort() #1 sortperm = array([5, 3, 4, 8, 9, 2, 0, 1, 7, 6])
rankperm = sortperm.argsort() #2 rankperm = array([6, 7, 5, 1, 2, 0, 9, 8, 3, 4])
split_ind = np.array([3,6,4,8,9]) # this is my split (random)
# split v and sortperm
v_split = v[split_ind] # v_split = array([10, 90, 20, 30, 40])
rankperm_split = rankperm[split_ind] # rankperm_split = array([1, 9, 2, 3, 4])
vsorted_dummy = np.ones(10)*-1 #3 allocate "empty" array[N]
vsorted_dummy[rankperm_split] = v_split
vsorted = vsorted_dummy[vsorted_dummy!=-1] # vsorted = array([ 10., 20., 30., 40., 90.])
Basically I have 2 questions:
Is double sorting necessary to create ranking array? (#1 and #2)
In the line #3 I'm allocating array[N]. This is very inefficent in terms of space because even if split size n << N I have to allocate whole array. The problem here is how to calculate rankperm_split. In the example original rankperm_split = [1,9,2,3,4] while it should be really [1,5,2,3,4]. This problem can be reformulated so that I want to create a "dense" integer array that has maximum gap of 1 and it keeps the ranking of the array intact.
UPDATE
I think that second point is the key here. This problem can be redefined as
A[N] - array of size N
B[N] - array of size N
I want to transform array A to array B so that:
Ranking of the elements stays the same (for each pair i,j if A[i] < A[j] then B[i] < B[j]
Array B has only elements from 1 to N where each element is unique.
A few examples of this transformation:
[3,4,5] => [1,2,3]
[30,40,50] => [1,2,3]
[30,50,40] => [1,3,2]
[3,4,50] => [1,2,3]
A naive implementation (with sorting) can be defined like this (in Python)
def remap(a):
a_ = sorted(a)
b = [a_.index(e)+1 for e in a]
return b

Resources