How can I check whether one array is a subset of another array, regardless of the order of elements?
a1 = [3, 6, 4]
a2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
...?
a1 is a subset of a2
Easiest may be:
(a1 - a2).empty?
Use sets. Then you can use set.subset?. Example:
require 'set'
a1 = Set[3,6,4]
a2 = Set[1,2,3,4,5,6,7,8,9]
puts a1.subset?(a2)
Output:
true
See it working online: ideone
The data structure you already have is perfect, just check the intersection:
(a1 & a2) == a1
Update: The comment discussing permutations is interesting and creative, but quite incorrect as the Ruby implementors anticipated this concern and specified that the order of the result is the order of a1. So this does work, and will continue to work in the future. (Arrays are ordered data structures, not sets. You can't just permute the order of an array operation.)
I do rather like Dave Newton's answer for coolness, but this answer also works, and like Dave's, is also core Ruby.
Perhaps not fast, but quite readable
def subset?(a,b)
a.all? {|x| b.include? x}
end
Related
I'd like to detect a "complete loop". Let's suppose that lists are connectable if the first value of a list is equal to the end value of another list. For example, we may have 5 lists like below.
a1 = [1, 14, 0]
a2 = [2, 14, 3]
a3 = [0, 14, 2]
a4 = [3, 14, 1]
a5 = [0, 14, 3]
where a1, a3, a2, and a4 can be connected to each other, forming a "complete loop" as a4 and a1 can also be connected. So the output shall be [a1, a3, a2, a4].
(It looked like as if it were an NP-Hard Problem, but I think I was wrong!) I've tried solutions such as Doubly Linked List or Hash Table, but it somehow then turned out to be recursive programming, which I'm terrible at and was not very successful.
Of course, I may just generate all the permutations and check one by one. Can there be a more beautiful way?
This is not NP-hard. Conceptually, this problem is known as 'cycle detection' and is a part of graph theory.
If you would like to see the code approaches to cycle detection, here is a decent beginner's tutorial:
https://www.tutorialspoint.com/Detect-Cycle-in-a-an-Undirected-Graph
https://www.techiedelight.com/check-undirected-graph-contains-cycle-not
If this problem was NP-hard, we wouldn't be able to do a lot of relatively-important things like dependency calculations and circular reference detection.
This question already has answers here:
Ruby - array intersection (with duplicates)
(7 answers)
Closed 1 year ago.
I have two arrays
a1 = [1, 1, 1, 2, 3, 3, 3]
a2 = [1, 1, 3, 3, 5, 5]
I want to return the values that appear in both arrays AND the exact amount that they appear
# => [1, 1, 3, 3]
I can't use a1 & a2 because that will return unique values ([1, 3])
What's the best way to achieve this?
It looks like what you have there are not really arrays, they are multisets or bags.
There is a general rule in programming: if you choose your data representation right, your algorithms become simpler.
So, if you use multisets instead of arrays, your problem will become trivial, since what you are looking for is literally just the intersection of two multisets.
Unfortunately, there is no multiset implementation in the core or standard libraries, but there are a couple of multiset gems available on the web. For example, there is the multimap gem, which also includes a multiset. Unfortunately, it needs a little bit of love and care, since it uses a C extension that only works until YARV 2.2. There is also the multiset gem.
require 'multiset'
m1 = Multiset.new(a1)
#=> #<Multiset:#3 1, #1 2, #3 3>
m2 = Multiset.new(a2)
#=> #<Multiset:#2 1, #2 3, #2 5>
m = m1 & m2
#=> #<Multiset:#2 1, #2 3>
Personally, I am not too big a fan of the inspect output, but we can see what's going on and that the result is correct: m contains 2 × 1 and 2 × 3.
If you really need the result as an Array, you can use Multiset#to_a:
m.to_a
#=> [1, 1, 3, 3]
At first I do get the intersection between a1 and a2 with (a1 & a2). After that I iterate over the intersection and check which array has a lower count of each element. The element gets than added to the result array as many times as it occurs in the array with the lower count using result.fill
a1 = [1, 1, 1, 2, 3, 3, 3]
a2 = [1, 1, 3, 3, 5, 5]
result = []
(a1 & a2).each do |e|
a1.count(e) < a2.count(e) ? result.fill(e, result.size, a1.count(e)) : result.fill(e, result.size, a2.count(e))
end
pp result
So, I need to add two arrays together to populate a third. EG
a = [1,2,3,4]
b = [3,4,5,6]
so that:
c = [4,6,8,10]
I read the answer given here: https://stackoverflow.com/questions/12584585/adding-two-ruby-arrays
but I'm using the codecademy labs ruby editor and it's not working there, plus the lengths of my arrays are ALWAYS going to be equal. Also, I don't have any idea what the method ".with_index" is or does and I don't understand why it's necessary to use ".to_i" when the value is already an integer.
It seems like this should be really simple?
a = [1,2,3,4]
b = [3,4,5,6]
a.zip(b).map { |i,j| i+j } # => [4, 6, 8, 10]
Here
a.zip(b) # => [[1, 3], [2, 4], [3, 5], [4, 6]]
and map converts each 2-tuple to the sum of its elements.
OPTION 1:
For a pure Ruby solution, try the transpose method:
a = [1,2,3,4]
b = [3,4,5,6]
c = [a, b].transpose.map{|x, y| x + y}
#=> [4,6,8,10]
OPTION 2:
If you're in a Rails environment, you can utilize Rails' sum method:
[a, b].transpose.map{|x| x.sum}
#=> [4,6,8,10]
EXPLANATION:
transpose works perfectly for your scenario, since it raises an IndexError if the sub-arrays don't have the same length. From the docs:
Assumes that self is an array of arrays and transposes the rows and columns.
If the length of the subarrays don’t match, an IndexError is raised.
I have created several arrays, containing multiple integers. Now i want the integers to be sorted, lowest first. Say for instance, i have this in an array: 6,6,1,2,4,4, i want it to be sorted: 1,2,4,4,6,6. Also, is there anyway i can make ruby recognize the 4 lowest values, and display them somehow? I have tried to mess around with .show, but since im quite new to programming i'm rather confused by the results i receive.
did you try this?
a = [6,6,1,2,4,4]
p a.sort
#=> [1, 2, 4, 4, 6, 6]
sort will sort in ascending order.
if you need them sorted in descending order, use sort with a block:
p a.sort {|a,b| b <=> a}
#=> [6, 6, 4, 4, 2, 1]
UPDATE: not sure how i missed the part about lowest values ...
thank you #Mladen
a.sort.take(4)
#=> [1, 2, 4, 4]
This is a follow up to this question:
Generate all "unique" subsets of a set (not a powerset)
My problem is the same, but I think there might be a more optimized solution when order of items in the new subsets and across the subsets needs to be preserved.
Example:
[1, 2, 3]
Would result in:
[[1], [2], [3]]
[[1, 2], [3]]
[[1], [2, 3]]
[[1, 2, 3]]
If I understand it correctly, you want to insert "delimiters" into a list, to partition it. Taking your example, and using the | character to indicate the delimiter,
1 2 3
1 2|3
1|2 3
1|2|3
are the solutions you want.
In a list (I'm calling it a list and not a set because you need the order preserved) of n elements, there are n-1 potential positions for a delimiter. In the example above, there are two positions. In each position, a delimiter might or might not be present.
You can use the binary representation of numbers from 0 to 2^(n-1) - 1 to list all possible arrangements of delimiters. In your example, this'll be number from 0..3.
0: 00
1: 01
2: 10
3: 11
I've already answered this question for Python, so I quickly ported my solution over to Ruby:
def spannings(lst)
return enum_for(:spannings, lst) unless block_given?
yield [lst]
(1...lst.size).each do |i|
spannings(lst[i..-1]) do |rest|
yield [lst[0,i]] + rest
end
end
end
p spannings([1,2,3,4]).to_a
See my other answer for a complete explanation of how and why this works.