What is an efficient way to find disjoint elements in two arrays? - arrays

I have the following arrays:
A = [1,2,3,4,5]
B = [2,6,7,1]
I want to find the disjoint elements, which are as follows:
output = [3,4,5,6,7]
I was able to achieve this as follows,
output = A + B - (A & B)
but it is inefficient, as I'm adding two arrays and then removing common elements. It is similar to finding non-intersecting elements. Can I do it better than this? If so, how?

How about just selecting elements in A not in B and elements in B not in A.
(A - B) + (B - A)

You could use Set
A = Set[1,2,3,4,5]
=> #<Set: {5, 1, 2, 3, 4}>
B = Set[2,6,7,1]
=> #<Set: {6, 1, 7, 2}>
C = A ^ B
=> #<Set: {5, 6, 7, 3, 4}>
C.to_a
=> [5, 6, 7, 3, 4]

Another one:
(A | B) - (A & B)
But you probably want to use your own version:
require 'benchmark'
n = 50000
A = (1..1000).to_a
B = [2,6,7,1]
Benchmark.bm do |x|
x.report { n.times do; (A + B) - (A & B); end }
x.report { n.times do; (A - B) + (B - A); end }
x.report { n.times do; (A | B) - (A & B); end }
x.report { n.times do; (Set[*A] ^ Set[*B]).to_a; end }
end
user system total real
2.200000 0.000000 2.200000 ( 2.208357)
9.600000 0.010000 9.610000 ( 9.591845)
10.630000 0.000000 10.630000 ( 10.621927)
31.420000 0.000000 31.420000 ( 31.418155)

Related

Minimum number of operations to make two arrays equal

Given 2 arrays of integers, A and B, an operation on array B is defined as follows:
B[i] = B[i]+2 and B[j] = B[j]-2, where i != j
i and j can be any indices and the above operation can be performed
any number of times such that i and j are not equal
a valid operation consists of both the addition and subtraction steps, both parts are mandatory
The array is considered equal if the frequency of all the elements is same, the array need not be ordered, find the minimum operations required
Input:
A = [ 2, 10, 14 ]
B = [ 6, 2, 18 ]
Output: 2
Explanation :
1st operation: select i=0; j=2;
B[i] += 2 i.e B[0]=8;
B[j] -= 2 i.e B[2] = 16;
B after 1st operation [8,2,16]
2nd operation: select i=0; j=2;
B[i] += 2 i.e B[0]=10;
B[j] -= 2 i.e B[2] = 14;
B after 2nd operation [10,2,14]
Order doesnt matter, so we have made the arrays equal return 2;
I am unable get an approach to solve this and couldn't find any similar questions, so posting this here, thanks in advance.
Assuming the arrays are solvable, then sort the arrays (by parity, and then by value), add up the absolute value of the deltas and divide by 4.
E.g.
A = [ 2, 10, 14 ], already sorted
B = [ 6, 2, 18 ], sorted becomes [2, 6, 18]
Sum of absolute value of deltas = 0 + 4 + 4 = 8. 8/4 = 2 so 2 moves.
A = [2, 10, 14]( % 2 == 0)
B = [2, 6, 18]( % 2 == 0)
another example
A = [1, 2, 5] -> [1, 5]( % 2 == 1) & [2]( % 2 == 0)
B = [1, 3, 4] -> [1, 3]( % 2 == 1) & [4]( % 2 == 0)
Notice that (a + k) mod k == a.
Assuming we already have a sorted array.
We divide the array into k parts, according to the mod k value of the element, then we sum all absolute differences, it's four times the answer.
k = 2
A.sort(key=lambda x: x % k)
B.sort(key=lambda x: x % k)
result = 0
n = len(A)
for i in range(n):
result += abs(A[i] - B[i])
print(result >> 2)
# A = [1, 2, 5]
# B = [1, 3, 4]
# result = 1
# A = [2, 10, 14]
# B = [6, 2, 18]
# result = 2
O(N log N) because of sorting.

Proper way to make array from integer division in Ruby

tl;dr I want to make an array from the division by 5 results:
20 => [5,5,5,5]
16 => [5,5,5,1]
7 => [5,2]
My current implementation is straightforward yet too large. How can I make it simpler and shorter?
max_count = 5
total_count = input_value
count_array = []
div = total_count / max_count
mod = total_count % max_count
div.times { count_array << max_count }
count_array << mod unless mod == 0
You don't need total_count.
div.times { count_array << max_count } is [max_count] * count_array
Using splat, we can simplify it further
max_count = 5
[*[max_count] * (input_value / max_count), input_value % max_count] - [0]
Alternatively, using divmod
max_count = 5
n, mod = input_value.divmod(max_count)
[*[max_count] * n, mod] - [0]
Last line can also be written as:
(Array.new(n) { max_count } << mod) - [0]
or as Stefan suggested in the comment, using Numeric#nonzero?:
Array.new(n, max_count).push(*mod.nonzero?)
One option more:
d = 5
n = 24
Array.new(n/d){d}.tap{ |a| a << n%d if (n%d).nonzero? }
#=> [5, 5, 5, 5, 4]
You can try this as well.
max=5
num=48
q, r=num.divmod(max) # => [9, 3]
Array.new.fill(max, 0, q).push(r.nonzero?).compact
# => [5, 5, 5, 5, 5, 5, 5, 5, 5, 3]
What about this?
[20].tap{|a| a.push(5, a.pop - 5) while a.last > 5} # => [5, 5, 5, 5]
[16].tap{|a| a.push(5, a.pop - 5) while a.last > 5} # => [5, 5, 5, 1]
[7] .tap{|a| a.push(5, a.pop - 5) while a.last > 5} # => [5, 2]

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)

How to sort one array based on another array using Ruby

There are two arrays:
A = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
B = [3, 4, 1, 5, 2, 6]
I want to sort B in a way that for all the elements of B that exists in A, sort the elements in the order that is in array A.
The desired sorted resulted would be
B #=> [1, 2, 3, 4, 5, 6]
I have tried to do
B = B.sort_by { |x| A.index }
but it does not work.
This question differs from the possible duplicates because it deals with presence of elements in the corresponding array and no hashes are present here.
It perfectly works:
▶ A = [1,3,2,6,4,5,7,8,9,10]
▶ B = [3,4,1,5,2,6]
▶ B.sort_by &A.method(:index)
#⇒ [1, 3, 2, 6, 4, 5]
If there could be elements in B that are not present in A, use this:
▶ B.sort_by { |e| A.index(e) || Float::INFINITY }
I would start by checking what elements from B exist in A :
B & A
and then sort it:
(B & A).sort_by { |e| A.index(e) }
First consider the case where every element of B is in A, as with the question's example:
A = [1,2,3,4,5,6,7,8,9,10]
B = [3,6,1,5,1,2,1,6]
One could write the following, which requires only a single pass through A (to construct g1) and a single pass through B.
g = A.each_with_object({}) { |n,h| h[n] = 1 }
#=> {1=>1, 2=>1, 3=>1, 4=>1, 5=>1, 6=>1, 7=>1, 8=>1, 9=>1, 10=>1}
B.each_with_object(g) { |n,h| h[n] += 1 }.flat_map { |k,v| [k]*(v-1) }
#=> [1, 1, 1, 2, 3, 5, 6, 6]
If there is no guarantee that all elements of B are in A, and any that are not are to be placed at the end of the sorted array, one could change the calculation of g slightly.
g = (A + (B-A)).each_with_object({}) { |n,h| h[n] = 1 }
This requires one more pass through A and through B.
Suppose, for example,
A = [2,3,4,6,7,8,9]
and B is unchanged. Then,
g = (A + (B-A)).each_with_object({}) { |n,h| h[n] = 1 }
#=> {2=>1, 3=>1, 4=>1, 6=>1, 7=>1, 8=>1, 9=>1, 1=>1, 5=>1}
B.each_with_object(g) { |n,h| h[n] += 1 }.flat_map { |k,v| [k]*(v-1) }
#=> [2, 3, 6, 6, 1, 1, 1, 5]
This solution demonstrates the value of a controversial change to hash properties that were made in Ruby v1.9: hashes would thereafter be guaranteed to maintain key-insertion order.
1 I expect one could write g = A.product([1]).to_h, but the doc Array#to_h does not guarantee that the keys in the hash returned will have the same order as they do in A.
You just missed x in A.index, so the query should be:
B = B.sort_by { |x| A.index(x) }

Define multiple variables at the same time in MATLAB

I want to define multiple variables at the same time.
For example, I want to define
a = 1
b = 2
c = 3
like this.
So I made a matrix with [a,b,c]:
x = [a, b, c];
y = [1, 2, 3];
x = y
So I want to get the following answer.
a = 1
b = 2
c = 3
If I use
[a, b, c] = deal(1, 2, 3)
then, I can get
a = 1
b = 2
c = 3
But I want to use matrix x instead of [a, b, c]
So if I use,
x = deal(1,2,3)
there is an error.
Is there any solution?
Maybe I don't understand the question but if you want to use the matrix x instead of [a, b, c] why don't you just define it as
x = [1, 2, 3];
From your question it sounds to me as if you are overcomplicating the problem. You begin by wanting to declare
a = 1;
b = 2;
c = 3;
but what you want instead according to the end of your question is
x = [1, 2, 3];
If you define x as above you can the refer to the individual elements of x like
>> x(1), x(2), x(3)
ans =
1
ans =
2
ans =
3
Now you have the best of both worlds with 1 definition. You can refer to a, b and c using x(1), x(2), x(3) instead and you've only had to define x once with x = [1, 2, 3];.
You cannot deal into a numeric array, but you can deal into a cell array and then concatenate all the elements in the cell array, like this:
[x{1:3}] = deal(1, 2, 3); % x is a cell array {1, 2, 3}
x = [x{:}]; % x is now a numeric array [1, 2, 3]

Resources