How do I convert a string to an array of arrays? - ruby

I have a string with an array of arrays inside:
"[[1, 2], [3, 4], [5, 6]]"
Can I convert this to the array of arrays, without using eval or a regular expression, gsub, etc.?
Can I make turn it into:
[[1, 2], [3, 4], [5, 6]]

How about the following?
require 'json'
arr = JSON.parse("[[1, 2], [3, 4], [5, 6]]") # => [[1, 2], [3, 4], [5, 6]]
arr[0] # => [1, 2]

The same can be done using Ruby standard libaray documentation - YAML:
require 'yaml'
YAML.load("[[1, 2], [3, 4], [5, 6]]")
# => [[1, 2], [3, 4], [5, 6]]

Related

Trouble transposing the array which has different size [duplicate]

I have an array:
arr=[[1,2,3],[4,5],[6]],
I have the following code:
arr.transpose
but it doesn't work,how to solve it?
I am getting
[[1,2,3],[4,5],[6]].transpose
IndexError: element size differs (2 should be 3)
from (irb):13:in `transpose'
from (irb):13
from /home/durrant
my solution:
arr.reduce(&:zip).map(&:flatten)
output:
[[1, 4, 6], [2, 5, nil], [3, nil, nil]]
Using zip as in Stefan's answer is the most straightforward, but if you insist on using transpose, then:
l = arr.map(&:length).max
arr.map{|e| e.values_at(0...l)}.transpose
# => [[1, 4, 6], [2, 5, nil], [3, nil, nil]]
Or without using either:
Array.new(arr.map(&:length).max){|i| arr.map{|e| e[i]}}
# => [[1, 4, 6], [2, 5, nil], [3, nil, nil]]
A similar answer was posted (but deleted) an hour earlier:
arr = [[1, 2, 3], [4, 5], [6]]
arr[0].zip(*arr[1..-1])
#=> [[1, 4, 6], [2, 5, nil], [3, nil, nil]]
The above is equivalent to:
[1, 2, 3].zip([4, 5], [6])
This approach assumes that your first sub-array is always the longest. Otherwise the result will be truncated:
arr = [[1, 2], [3, 4, 5], [6]]
arr[0].zip(*arr[1..-1])
#=> [[1, 3, 6], [2, 4, nil]] missing: [nil, 5, nil]
If the length of the subarrays don’t match, an IndexError is raised.
irb(main):002:0> arr=[[1,2,3],[4,5],[6]]
=> [[1, 2, 3], [4, 5], [6]]
irb(main):003:0> arr.transpose
IndexError: element size differs (2 should be 3)
from (irb):3:in `transpose'
from (irb):3
from /Users/liuxingqi/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'
should be:
irb(main):004:0> arr=[[1,2,3],[4,5,6]]
=> [[1, 2, 3], [4, 5, 6]]
irb(main):005:0> arr.transpose
=> [[1, 4], [2, 5], [3, 6]]
or
irb(main):006:0> arr=[[1,2],[3,4],[5,6]]
=> [[1, 2], [3, 4], [5, 6]]
irb(main):007:0> arr.transpose
=> [[1, 3, 5], [2, 4, 6]]

Comparing 2d arrays together

I have four 2d arrays of varying lengths. Is there a way to compare them to make sure none of the arrays share a value? Is there a simple way to code it or a gem I could use?
To back my question up with an example:
array1 = [[2,3],[2,4]]
array2 = [[1,3],[2,3],[3,3]]
array3 = [[5,3],[6,3],[7,3],[8,3],[9,3]]
I want a checker that would let me know that array1 and array2 have an element the same.
Is this doable?
You might do it as follows.
Code
def shared_values?(*arr)
a = arr.map(&:uniq).reduce(:+)
a.size > a.uniq.size
end
Examples
array1 = [[2, 3], [2, 4]]
array2 = [[1, 3], [2, 3], [3, 3]]
array3 = [[5, 3], [6, 3], [7, 3],[8, 3],[9, 3]]
shared_values? array1, array2, array3 #=> true
array1 = [[2, 4]]
shared_values? array1, array2, array3 #=> false
array1 = [[2, 4], [2, 4]]
shared_values? array1, array2, array3 #=> false
array1 = [[2, 3], [2, 4], [2, 4]]
shared_values? array1, array2, array3 #=> false
Explanation
For the last example above:
arr = [array1, array2, array3]
#=> [ [[2, 3], [2, 4], [2, 4]],
# [[1, 3], [2, 3], [3, 3]],
# [[5, 3], [6, 3], [7, 3], [8, 3], [9, 3]] ]
a = arr.map(&:uniq)
#=> [ [[2, 3], [2 ,4]],
# [[1, 3], [2, 3], [3, 3]],
# [[5, 3], [6, 3], [7, 3], [8, 3], [9, 3]] ]
b = a.reduce(:+)
#=> [[2, 3], [2, 4], [1, 3], [2, 3], [3, 3],
# [5, 3], [6, 3], [7, 3], [8, 3], [9, 3]]
c = b.uniq
#=> [[2, 3], [2, 4], [1, 3], [3, 3],
# [5, 3], [6, 3], [7, 3], [8, 3], [9, 3]]
b.size > c.size
# 10 > 9 #=> true
arr.map(&:uniq) is the same as:
arr.map { |a| a.uniq }
a.reduce(:+) uses the form of Enumerable#reduce that takes an argument that is a symbol, naming a method to be applied to each element of arr, the result being the sum of the three arrays that comprise the elements of b.
If the arrays are in a consistent format, like all numbers and not a mix of floating point and strings, you can do this:
array1 & array2
# => [[2, 3]]
That means to test if they overlap:
(array1 & array2).any?
If you can be assured each of the elements in all of the arrays are unique, then you can test quickly if there are any duplicates:
sum = array1 + array2 + array3 + array4
sum.length == sum.uniq.length
If each array may contain duplicates then you'd need to pair them off and compare A vs. B for all possible pairs.

Creating pairs from an Array?

Is there a simple way to create pairs from an array?
For example, if I have an array [1,2,3,4] how would I go about trying to return this array?
[[1,2], [1,3], [1,4], [2,1], [2,3], [2,4], [3,1], [3,2], [3,4], [4,1], [4,2], [4,3]]
Every element is paired with every other other element except itself, and duplicates are allowed.
You can use Array#permutation for this:
[1,2,3,4].permutation(2).to_a
# => [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4, 2], [4, 3]]
[1,2,3,4].permutation(2).map{ |n| "(#{ n.join(",") })" }
# => ["(1,2)", "(1,3)", "(1,4)", "(2,1)", "(2,3)", "(2,4)", "(3,1)", "(3,2)", "(3,4)", "(4,1)", "(4,2)", "(4,3)"]

Creating permutations from a multi-dimensional array in Ruby

I have the following multi-dimensional array in Ruby:
[[1,2], [3], [4,5,6]]
I need to have the following output:
[[1,3,4], [1,3,5], [1,3,6], [2,3,4], [2,3,5], [2,3,6]]
I have tried creating a recursive function, but I'm not having much luck.
Are there any Ruby functions that would help with this? Or is the only option to do it recursively?
Thanks
Yup, Array#product does just that (Cartesian product):
a = [[1,2], [3], [4,5,6]]
head, *rest = a # head = [1,2], rest = [[3], [4,5,6]]
head.product(*rest)
#=> [[1, 3, 4], [1, 3, 5], [1, 3, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6]]
Another variant:
a.inject(&:product).map(&:flatten)
#=> [[1, 3, 4], [1, 3, 5], [1, 3, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6]]

Sorting an array by two values

Suppose I have
an_array = [[2, 3], [1, 4], [1, 3], [2, 1], [1, 2]]
I want to sort this array by the first value of each inner array, and then by the second (so the sorted array should look like this: [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3]])
What's the most readable way to do this?
This is the default behavior for sorting arrays (see the Array#<=> method definition for proof). You should just be able to do:
an_array.sort
If you want some non-default behaviour, investigate sort_by (ruby 1.8.7+)
e.g. sort by the second element then by the first
a.sort_by {|e| [e[1], e[0]]} # => [[2, 1], [1, 2], [1, 3], [2, 3], [1, 4]]
or sort by the first element ascending and then the second element descending
a.sort_by {|e| [e[0], -e[1]]} # => [[1, 4], [1, 3], [1, 2], [2, 3], [2, 1]]
an_array.sort

Resources