Merging 2 Arrays based on one column [closed] - ruby

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions must demonstrate a minimal understanding of the problem being solved. Tell us what you've tried to do, why it didn't work, and how it should work. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I have two arrays:
a = [[1234,1],[2134,0],[4321,0],[2221,3]]
b = [[2134,1],[4321,3]]
I want to merge them based on the first elements of a for the following result:
c = [[1234,1],[2134,1],[4321,3],[2221,3]]
I want to replace 0's in a by the value in b if the first element match. The first element is unique in a and b.
How do I do this?
Thanks in advance,

The Hash#merge function lets you specify a block to define what to do with the values.
a = [[1234,1],[2134,0],[4321,0],[2221,3]]
b = [[2134,1],[4321,3]]
c = Hash[a].merge(Hash[b]) { |key, old, new| old+new }.to_a
# => [[1234, 1], [2134, 1], [4321, 3], [2221, 3]]
See the Hash#merge documentation.
In this case I did the merge through building the sum of the values. You might want to choose the largest value, or some other strategy which fits you.
Disclaimer: This approach does not work, if a (or b) contains Arrays having the same first value. Example [[1, 1], [1, 4], [2, 8]]. It is not specified in your question if that can happen.

Given
a = [[1234,1],[2134,0],[4321,0],[2221,3]]
and
b = [[2134,1],[4321,3]]
You could transform these arrays into hashes, perform the merge, then transform the result into an array again.
Hash[a].merge(Hash[b]).to_a
#=> [[1234, 1], [2134, 1], [4321, 3], [2221, 3]]

Here's one possibility:
a = [[1234,1],[2134,0],[4321,0],[2221,3]]
b = [[2134,1],[4321,3]]
a.zip(b).flatten(1).uniq(&:first)
# => [[1234, 1], [2134, 1], [4321, 3], [2221, 3]]

[*a, *b].group_by(&:first).map{|k, v| [k, v.map(&:last).inject(:+)]}

Just reverse the arrays and call unique:
(b + a).uniq(&:first)
This works because Array#+ is a non-mutating version of Array#concat. It'll create a new ordered array. Whichever array is first, will take precedence in the output. When uniq is called, it will enumerate over the array in order, allowing you to just get the first instance of the first column.
You can do this for n arrays:
[b,d,c,a].reduce(&:+).uniq(&:first)

Related

Fastest way to split ruby array following a structure [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I'm looking for the fastest way to split an array into sub-arrays with different size. The size of every array is driven by a configuration file.
Example:
c = [1,2,3,4,5,6,7,8]
My configuration file:
block
contents: 3
type: ...
scope ...
block
contents: 1
type: ...
scope ...
block
contents: 2
type: ...
scope ...
block
contents: 2
type: ...
scope ...
c.size is equal to the sum of the content number of every block.
I must split my array into 'n' arrays where n is the number of blocks I define in my config file and the size of every array is the number of contents defined in that block.
The result with the given array and config file is:
[1,2,3]
[4]
[5,6]
[7.8]
Any idea with good performance result?
A slight variant of Matt's answer:
If you read the values from the file into:
a = [3,1,2,2]
you can then do this:
a.each_with_object([]) {|e,b| b << c.shift(e)}
#=> [[1, 2, 3], [4], [5, 6], [7, 8]]
c = [1,2,3,4,5,6,7,8]
d = [3,1,2,2]
d.map { |n| c.shift n } # => [[1, 2, 3], [4], [5, 6], [7, 8]]
This destroys the original c.

Adding two arrays in Ruby when the array length will always be the same

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.

Best way to handle a ratings system [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I'm trying to implement a comparison rating system and I'm having difficulties finding the best way to handle this, especially from a database perspective.
Let's use food for an example.
The user is given pictures of two different foods and he chooses which one he likes better. He is then shown two more foods (one could be the same or they could both be different) and the user again selects. He continues to do this over and over and in doing so the application will TELL the user what his favorite food is, based solely on him saying which ones he likes more than others and comparing all these comparisons and displaying the results.
I've thought of just keeping track of the total likes/dislikes of each item, and I've also considered keeping track of every single choice in a massive database. I'm sure there's a way I've overlooked that is efficient for this kind of system.
Basically I'm looking not only for an efficient algorithm but also the best way to store this in a database.
Thanks for the help.
I'd just keep a database of triplets (user_id, preferred_id, dispreferred_id) corresponding to each choice.
EDIT: Had a bit of time to play with this. The following would be slow for millions of ratings, and gobble up memory, too, but might give you ideas. If you do go with this, you should probably run in asynchronously from crontab, rather by on-demand.
require 'set'
choices = [
[1, 4],
[1, 5],
[2, 3],
[2, 4],
[3, 1],
[4, 2],
[4, 3],
[5, 1],
[6, 7],
[8, 4],
]
dominates = Hash.new { |hash, key| hash[key] = Set.new }
choices.each do |p, d|
dominates[p].add(d)
end
prev_dominates = nil
while dominates != prev_dominates
prev_dominates = Hash.new
dominates.each { |big, smalls| prev_dominates[big] = smalls.clone }
prev_dominates.each do |big, smalls|
smalls.each do |small|
if prev_dominates.include?(small)
prev_dominates[small].each do |smaller|
if smaller != big and !prev_dominates[smaller].include?(big)
dominates[big] << smaller
end
end
end
end
end
end
top = dominates.max_by { |big, smalls| smalls.size }[0]
puts dominates.inspect
puts "BEST: #{top}"
The top node is the one that ends up dominating the most other nodes. However, given that the graph can be cyclic, we cut the cycle if another node would have completed the cycle sooner.

Get all possible subsets - preserving order

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.

Difference Between map and each [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Ruby - What is the difference between map, each and collect?
I have looked in Ruby-Doc also but i cant understand the difference between
map
each
iterators.It would be great if you could give an example and explain.
each simply iterates over the given enumerable, running the block for each value. It discards the return value of the block, and each simply returns the original object it was called on:
[1, 2, 3].each do |x|
x + 1
end # => [1, 2, 3]
This is simply a nicer, more universal way of doing a traditional iterating for loop, and each is much preferred over for loops in Ruby (in fact, I don't think I've ever used a for loop in Ruby).
map, however, iterates over each element, using the return value of the block to populate a new array at each respective index and return that new array:
[1, 2, 3].map do |x|
x + 1
end # => [2, 3, 4]
So it “maps” each element to a new one using the block given, hence the name “map”. Note that neither each nor map themselves modify the original collection. This is a concise, functional alternative to creating an array and pushing to it in an iterative loop.
each returns the original object. It's used to run an operation using each element of an array without collecting any of the results. For example, if you want to print a list of numbers, you might do something like this:
arr = [1, 2, 3, 4]
arr.each { |n| puts n }
Now, that puts method above actually returns nil. Some people don't know that, but it doesn't matter much anyway; there's no real reason to collect that value (if you wanted to convert arr to strings, you should be using arr.map(&:to_s) or arr.map { |n| n.to_s }.
map returns the results of the block you pass to it. It's a great way to run an operation on each element in an array and retrieve the results. If you wanted to multiple every element of an array by 2, this is the natural choice. As a bonus, you can modify the original object using map!. For example:
arr = [1, 2, 3, 4]
arr.map! { |n| n * 2}
# => [2, 4, 6, 8]

Resources