The question is mostly in the title:
given an array
array = [{x: 1, y: "jacksonville"},
{x: 2, y: "atlanta"},
{x: 1, y: "tampa"},
{x: 2, y: "atlanta"},
{x: 2, y: "jacksonville"},
{x: 2, y: "miami"}, ]
Whats a good method to attain the following result
array = [{x: 3, y: "jacksonville",
{x: 4, y: "atlanta"},
{x: 1, y: "tampa"},
{x: 2 ,y: "miami"}]
The input are a simplistic version of what i'm really working with but as you can see i'm attempting to remove duplicates of the y values but retain the x values, I know i can run a merge on each hash combining two hashes by passing a black to Hash#merge but i'm having difficulty comparing all hashes to each other or finding the duplicates. Looking for a performant solution.
Here:
array.group_by{|e|e[:y]}.map{|k,v|{x:v.reduce(0){|a,b|a+b[:x]},y:k}}
First of all, you must have to create a convenient way to index y data. I would use Hash for that:
h = array.inject({}) do |ret, item|
ret[item[:y]] ||= 0 # initialize each item
ret[item[:y]] += item[:x] # increment count
ret # return the hash
end
With this Hash on hand, you can generate the new array:
h.map {|key, value| {x: value, y: key}}
Related
RUBY the goal is to get the max value from each of the four zones and get their sum.
UPDATE I came up with a solution, I'm sorry about the mixup. It turned out that the matrix is a 2n x 2n matrix so it could have been greater or smaller than 4x4 in fact it. The solution i wrote below worked on all of the test cases. Here is a link to the problem
I tried doing matrix.transpose then I tried reversing the specific array, that didn't work for all edge cases.
Here is the code for that
def flippingMatrix(matrix)
2.times do
matrix = matrix.transpose
matrix = matrix.map do |array|
if (array[-1] == array.max) || (array[-2] == array.max)
array.reverse
else
array
end
end
end
return matrix[0][0] + matrix[0][1] + matrix[1][0] + matrix[1][1]
end
I gave up and tried the below, which in my mind works, it also works for most edge cases but not all.
But i'm getting an error (undefined method `[]' for nil:NilClass (NoMethodError))
keep in mind when I print the results or spot_1, spot_2, spot_3, or spot_4 I get the correct answer. does anyone have an idea why this is happening?
Here is a matrix that FAILED
[
[517, 37, 380, 3727],
[3049, 1181, 2690, 1587],
[3227, 3500, 2665, 383],
[4041, 2013, 384, 965]
]
**expected output: 12,881 (this fails)**
**because 4041 + 2013 + 3227 + 3500 = 12,881**
Here is a matrix that PASSED
[
[112, 42, 83, 119],
[56, 125, 56, 49],
[15, 78, 101, 43],
[62, 98, 114, 108],
]
**expected output: 414 (this passes)**
Here is the code
def flippingMatrix(matrix)
# Write your code here
spot_1 = [matrix[0][0] , matrix[0][3] , matrix[3][0] , matrix[3][3]].max
spot_2 = [matrix[0][1] , matrix[0][2] , matrix[3][1] , matrix[3][2]].max
spot_3 = [matrix[1][0] , matrix[1][3] , matrix[2][0] , matrix[2][3]].max
spot_4 = [matrix[1][1] , matrix[1][2] , matrix[2][1] , matrix[2][2]].max
return (spot_1 + spot_2 + spot_3 + spot_4)
end
I will answer your question and at the same time suggest two other ways to obtain the desired sum.
Suppose
arr = [
[ 1, 30, 40, 2],
[300, 4000, 1000, 200],
[400, 3000, 2000, 100],
[ 4, 10, 20, 3]
]
First solution
We see that the desired return value is 4444. This corresponds to
A B B A
C D D C
C D D C
A B B A
First create three helper methods.
Compute the largest value among the four inner elements
def mx(arr)
[arr[1][1], arr[1][2], arr[2][1], arr[2][2]].max
end
mx(arr)
#=> 4000
This is the largest of the "D" values.
Reverse the first two and last two rows
def row_flip(arr)
[arr[1], arr[0], arr[3], arr[2]]
end
row_flip(arr)
#=> [[300, 4000, 1000, 200],
# [ 1, 30, 40, 2],
# [ 4, 10, 20, 3],
# [400, 3000, 2000, 100]]
This allows us to use the method mx to obtain the largest of the "B" values.
Reverse the first two and last two columns
def column_flip(arr)
row_flip(arr.transpose).transpose
end
column_flip(arr)
#= [[ 30, 1, 2, 40],
# [4000, 300, 200, 1000],
# [3000, 400, 100, 2000],
# [ 10, 4, 3, 20]]
This allows us to use the method mx to obtain the largest of the "C" values.
Lastly, the maximum of the "A" values can be computed as follows.
t = row_flip(column_flip(arr))
#=> [[4000, 300, 200, 1000],
# [ 30, 1, 2, 40],
# [ 10, 4, 3, 20],
# [3000, 400, 100, 2000]]
mx(column_flip(t))
#=> 4
The sum of the maximum values may therefore be computed as follows.
def sum_max(arr)
t = column_flip(arr)
mx(arr) + mx(row_flip(arr)) + mx(t) + mx(row_flip(t))
end
sum_max(arr)
#=> 4444
Second solution
Another way is the following:
[0, 1].product([0, 1]).sum do |i, j|
[arr[i][j], arr[i][-j-1], arr[-i-1][j], arr[-i-1][-j-1]].max
end
#=> 4444
To see how this works let me break this into two statements add a puts statement. Note that, for each of the groups A, B, C and D, the block variables i and j are the row and column indices of the top-left element of the group.
top_left_indices = [0, 1].product([0, 1])
#=> [[0, 0], [0, 1], [1, 0], [1, 1]]
top_left_indices.sum do |i, j|
a = [arr[i][j], arr[i][-j-1], arr[-i-1][j], arr[-i-1][-j-1]]
puts a
a.max
end
#=> 4444
The prints the following.
[1, 2, 4, 3]
[30, 40, 10, 20]
[300, 200, 400, 100]
[4000, 1000, 3000, 2000]
ahhh I came up with an answer that answers all edge cases. I originally saw something like this in Javascript and kind of turned it into Ruby. Apparently some of the hidden edge cases (that were hidden) weren't all 4 by 4 some were smaller and some larger, that was the cause of the nil error.
Here is the solution:
def flippingMatrix(matrix)
total = []
(0...(matrix.length/2)).each do |idx1|
(0...(matrix.length/2)).each do |idx2|
total << [matrix[idx1][idx2],
matrix[(matrix.length - 1)-idx1][idx2],
matrix[idx1][(matrix.length - 1)-idx2],
matrix[(matrix.length - 1)-idx1][(matrix.length - 1)-idx2]].max
end
end
total.sum
end
Thank you all for your support! I hope this helps someone in the near future.
In my case, value has the priority, so I need to sort the array first by value, then alphabetically by key. Which algorithm/technique to use?
Here is an example:
[ [
d: 1, r: 0,
z: 0, z: 0,
r: 0, => a: 1,
a: 1, d: 1,
e: 1 e: 1
] ]
I was thinking of splitting the array in two groups (first group would me made of elements with value 0; second group of elements with value 1), sort each, then merge them again. But I am looking for a better solution.
Names such as map, filter or sum are generally understood by every resonably good programmer.
I wonder whether the following function f also has such a standard name:
def f(data, idx): return [data[i] for i in idx]
Example usages:
r = f(['world', '!', 'hello'], [2, 0, 1, 1, 1])
piecePrice = [100, 50, 20, 180]
pieceIdx = [0, 2, 3, 0, 0]
total Price = sum(f(piecePrice, pieceIdx))
I started with map, but map is generally understood as a function that applies a function on each element of a list.
I am using Ruby 2.3.1 and I cannot tell if I've encountered a bug or if this is intended behavior.
If you create an NxN matrix by making nested arrays, as such:
matrix = [[0]*5]*5
and then set the elements on the diagonals, as such:
(0..4).each {|i| matrix[i][i] = i}
this ends up affecting every column in every row:
[
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4],
[0, 1, 2, 3, 4]
]
Is this intended behavior?
P.S. I do not want to use Ruby's Matrix library, but would rather work with plain arrays.
Thanks in advance :)
In Ruby, arrays are, behind the scenes, objects of type array, which can contain primitive types and references to other objects. Now, this last bit is important - the array doesn't contain the object itself, but instead a pointer to it, which is interpreted as necessary when the programmer asks for it.
So the OP's original initialization code
matrix = [[0]*5]*5
Really creates a single array object containing 5 0s, and then copies the pointer to it 5 times. This also happens when you do
matrix = Array.new(5, Array.new(5, 0))
for precisely the same reason. So, as posted in the comments, the idiomatically correct Ruby way to create an array of 5 different array objects is
matrix = Array.new(5){Array.new(5, 0)}
Which yields a single array that contains pointers to 5 different array objects, preventing the issue encountered by the OP. Full documentation on the behaviour of Ruby arrays can be found at this finely-crafted link.
You don't need to change the diagonal to observe that behaviour; just change any element, say
matrix[1][1] = 1
Then
matrix
#=> [[0, 1, 0, 0, 0], [0, 1, 0, 0, 0], [0, 1, 0, 0, 0],
# [0, 1, 0, 0, 0], [0, 1, 0, 0, 0]]
Consider
matrix.map { |row| row.object_id }
#=> [70153694327100, 70153694327100, 70153694327100,
# 70153694327100, 70153694327100].
This shows that all elements ("rows") of matrix are the same object, ergo, if that object is changed, all elements of matrix are affected. matrix = [[0]*5]*5 is equivalent to
matrix = Array.new(5, Array.new(5,0))
(See Array::new, expecially "Common gotchas".) What you want (as #Sebastian notes) is
matrix = Array.new(5) { Array.new(5,0) }
#=> [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
so that
matrix[1][1] = 1
only affects that one element:
matrix
#=> [[0, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0],
# [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]
matrix = [[0]*5]*5
Let's break this down:
a = [0]*5
Create an array of 5 zeros; this is an array of integers.
matrix = [a] * 5
Create an array of 5 references to the same array a.
So of course when you modify one, the others will be modified; it's the same array.
I don't know Ruby, so please feel free to correct any incorrect terminology.
I was trying to understand the local variable creation inside the pipe(|) when writing code with block. And also tried the same in my IRB below codes.
[1,2,3].each {|x;y| y=x; print y}
#123=> [1, 2, 3]
[1,2,3].each {|x;y = 0| y=x; print y}
#SyntaxError: (irb):1: syntax error, unexpected '=', expecting '|'
#[1,2,3].each {|x;y = 0| y=x; print y}
^
#(irb):1: syntax error, unexpected '}', expecting $end
# from C:/Ruby193/bin/irb:12:in `<main>'
But couldn't understand what's happened with the second code,while the first one is perfect.
Could anyone tell me the difference between |x,y| and |x;y=0| ? Hope answer to this
question will make sense to me.
Again below works perfectly:
a = "hello world".split(//).each{ |x,newstr = Array.new() | newstr = x.capitalize;puts newstr }
#H
#E
#L
#L
#O
#
#W
#O
#R
#L
#D
#=> ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
Starting from Ruby 1.9, it is possible to declare a local variable in a block by separating it from block parameter with ;. In your example, x is then a block parameter, and y is a local variable. The following code illustrates it well.
> [1,2,3].each {|x; y| puts "x: #{x} - y: #{y}"}
x: 1 - y:
x: 2 - y:
x: 3 - y:
=> [1, 2, 3]
As y is not initialized, it has no value. Syntactically, you cannot init a local block variable directly between the pipes | | as you did in your second example. It's just forbidden.
However, in Ruby 1.9, you can set default value for block parameters. Indeed,
> [1,2,3].each {|x,y=0| puts "x: #{x} - y: #{y}"}
x: 1 - y: 0
x: 2 - y: 0
x: 3 - y: 0
=> [1, 2, 3]
is syntactically correct. This time y is a block parameter with default value 0. You can illustrate the difference with the following:
> { one: 1, two: 2, three: 3}.each {|x,y=0| puts "x: #{x} - y: #{y}"}
x: one - y: 1
x: two - y: 2
x: three - y: 3
=> {:one=>1, :two=>2, :three=>3}
;y is used to work around Ruby's scoping (shadowing outer variables), and does not accept a value because it's inside ||