Can not initialize array correctly - ruby

I've been trying to code some algorithm in a minified manner>.
I believe that typical 2d array defining is looks too unwieldy
mx = Array.new(N) { Array.new(N) }
I am trying to use another hint, but it's behaviour is a bit strange for me:
mx = [[!:&]*n]*n
Take a look:
#square matrix n*n
n=3
mx = [[!:&]*n]*n
#=> [[false, false, false], [false, false, false], [false, false, false]]
mx[0][0]=true
mx
#=> [[true, false, false], [true, false, false], [true, false, false]]
# true true true ????
#.
How should I tame my array?
repl.it_snippet: avaiable

This is because the sub arrays are the same instance
#square matrix n*n
n=3
mx = [[!:&]*n]*n
#=> [[false, false, false], [false, false, false], [false, false, false]]
mx[0] === mx[1]
# true
mx[1] === mx[2]
# true
to fix the code, add something like that
n=3
mx = [[!:&]*n]*n
mx = mx.flatten.each_slice(n).to_a
mx[0][0] = true
mx
# [[true, false, false], [false, false, false], [false, false, false]]
or
n=3
mx = ([!:&]*n*n).each_slice(n).to_a
mx[0][0] = true
mx
# [[true, false, false], [false, false, false], [false, false, false]]

Related

Rails merge array into array of arrays

I'm new to Ruby on Rails and I have a weird array situation that I'm unable to figure out how to execute efficiently.
I have this starting array of arrays:
[["6884", true], ["8456", false], ["5631", false]]
Then I have another 1D array:
["6884", "8023", "9837"]
I want to merge the 1D array into the array of arrays by appending the value to the end of the array at the same index in the 2D array.
So the final product should be:
[["6884", true, "6884"], ["8456", false, "8023"], ["5631", false, "9837]]
So the value at index 0 in the 1D array is appended to the end of the array at index 0 in the 2D array, and so on for each element in the 1D array. Is there an easy Ruby way to accomplish this?
You can do it with zip and flatten methods like this:
a = [["6884", true], ["8456", false], ["5631", false]]
b = ["6884", "8023", "9837"]
a.zip(b)
# [[["6884", true], "6884"], [["8456", false], "8023"], [["5631", false], "9837"]]
# Then use flatten to this array:
a.zip(b).map(&:flatten)
# [["6884", true, "6884"], ["8456", false, "8023"], ["5631", false, "9837"]]
Further to Mehmet Adil İstikbal's answer, here's another approach -- just to show that There's More Than One Way To Do It:
a = [["6884", true], ["8456", false], ["5631", false]]
b = ["6884", "8023", "9837"]
a.map.with_index { |item, index| item.push(b[index]) }
# => [["6884", true, "6884"], ["8456", false, "8023"], ["5631", false, "9837"]]
a2 = [["6884", true], ["8456", false], ["5631", false]]
a1 = ["6884", "8023", "9837"]
a2.zip(a1).map { |e2, e1| [*e2, e1] }
or, to avoid the creation of the temporary array a2.zip(a1),
a1.each_index.map { |i| [*a2[i], a1[i]] }
Both return
[["6884", true, "6884"], ["8456", false, "8023"], ["5631", false, "9837"]]
Note that neither expression mutates a2 or a1. See Array#each_index (which, without a block, returns an enumerator) and Enumerable#map.
If you want to modify the first array you can pass a block to zip to append the latter elements to the corresponding sub-array:
a = [["6884", true], ["8456", false], ["5631", false]]
b = ["6884", "8023", "9837"]
a.zip(b) { |ary, el| ary << el }
a
# => [["6884", true, "6884"], ["8456", false, "8023"], ["5631", false, "9837"]]

What's the fastest way to find out where a list of numpy arrays are equal?

I have a list of numpy arrays, each of which are from an image, hence they're three-dimensional (height, width, channel). I need to know at which (r, w, c) points these are equal.
EDIT: More to the point, I'm trying to find out where these images differ. If there is a better way to do that, that would be good too.
Is this the sort of thing you are trying to do?
Define two 3d 'images' (small for convenience):
In [417]: img1=np.zeros((4,5,3),int); img2=np.zeros((4,5,3),int)
In [418]: img1[1:3,1:4,:]=[1,0,2] # different 'color' in the middle
In [419]: img2[1:3,1:4,:]=[2,1,0]
In [421]: img1!=img2
Out[421]:
array([[[False, False, False],
[False, False, False],
[False, False, False],
[False, False, False],
[False, False, False]],
[[False, False, False],
[ True, True, True],
...,
[False, False, False]]], dtype=bool)
If we are just interested in the points where they differ, and not the colors, we can apply all or any (I'll let you sort that out):
In [422]: (img1!=img2).all(axis=2)
Out[422]:
array([[False, False, False, False, False],
[False, True, True, True, False],
[False, True, True, True, False],
[False, False, False, False, False]], dtype=bool)
and use where (or nonzero) to find the indices of those points.
In [423]: np.where((img1!=img2).all(axis=2))
Out[423]:
(array([1, 1, 1, 2, 2, 2], dtype=int32),
array([1, 2, 3, 1, 2, 3], dtype=int32))
For multiple images we could 'stack' them, and do the same sort of equality tests
In [429]: imgs=np.array([img1,img2]) # 4d (2, 4, 5, 3)
In [430]: (imgs==imgs[0,...]).all(axis=0).all(axis=-1)
Out[430]:
array([[ True, True, True, True, True],
[ True, False, False, False, True],
[ True, False, False, False, True],
[ True, True, True, True, True]], dtype=bool)
Again I'm focusing on how you can perform comparisons across multiple dimensions.

On average, set true on every fifth item, but not in even order

I have a collection with 100 items.
In an iteration I want to set an object attribute to true on 20 % of the items.
But I don't want the setting of true to occur evenly, i.e. on every fifth item.
It's even OK if not exactly 20 % gets true, as long as the setting is not set evenly.
An inefficient but concise way of accomplishing this would be to shuffle your array, slice the first 20 elements, then set the attributes on them.
items.shuffle[0..19].each do |item|
item.foo = true
end
If you care about efficiency, you may want to look into modifying the Fisher Yates algorithm.
You can use rand:
def true_20_percent_of_the_time
rand(5) == 0
end
If you're generating the array:
ary = Array.new(2, true) + Array.new(8, false)
ary # => [true, true, false, false, false, false, false, false, false, false]
ary.shuffle # => [false, false, true, false, false, false, false, false, false, true]
That only uses 10 elements as an example, but I'm sure you can figure out how to adjust the count.
The above can be reduced to:
ary = (Array.new(2, true) + Array.new(8, false)).shuffle
# => [false, false, true, false, true, false, false, false, false, false]
And that can be reduced to:
ary = (([true] * 2) + ([false] * 8)).shuffle
# => [false, false, false, true, false, false, true, false, false, false]
If it's a pre-existing array:
ARRAY_SIZE = 10
ary = [false] * ARRAY_SIZE
Then you can slice it and reassign the number of true elements needed:
ary[0, (ARRAY_SIZE * 0.20).to_i] = [true] * (ARRAY_SIZE * 0.20)
ary # => [true, true, false, false, false, false, false, false, false, false]
And then shuffle it:
ary.shuffle # => [true, false, false, false, false, false, false, false, false, true]
Let's say you have the array
a = Array.new(21) { |i| i }
#=> [0, 1, 2, 3,..., 19, 20]
and you wanted to choose exactly
(a.size/5.0).round #=> 4
elements randomly. Then you could write:
#lucky_ones = [*(0...a.size)].sample((a.size/5.0).round)
#=> [6, 12, 3, 9]
a.each_with_index do |e,i|
puts "Wow! I've been selected. I'm #{e}" if #lucky_ones.include? i
end
Wow! I've been selected. I'm 3
Wow! I've been selected. I'm 6
Wow! I've been selected. I'm 9
Wow! I've been selected. I'm 12

Using Ruby, what is a simple way to count how many true in each column of n x m array?

Given an n x m array of boolean:
[[true, true, false],
[false, true, true],
[false, true, true]]
what is a simple way that can return "how many true are there in that column?"
the result should be
[1, 3, 2]
Use transpose to get an array where each subarray represents a column and then map each column to the number of trues in it:
arr.transpose.map {|subarr| subarr.count(true) }
Here's a version with inject that should run on 1.8.6 without any dependencies:
arr.transpose.map {|subarr| subarr.inject(0) {|s,x| x ? s+1 : s} }
array = [[true, true, false],
[false, true, true],
[false, true, true]]
array.transpose.map {|x| x.count {|y| y}}
Here's another solution:
b.transpose.collect{|x| x.reject{|y| y != true}.length}
a=[[true, true, false],
[false, true, true],
[false, true, true]]
a.transpose.map{|c|c.count(true)}
sneaky way of saving one more character
a.transpose.map{|c|c.count(!!0)}
As Jonas points out it is possible to golf this some more
a.transpose.map{|c|c.count !!0}

pathfinding conditions def

Ok so I had to crack a Heineken for this one. Trying to solve a shortest path problem with a text file.
My research took me to:
link text
link text
pretty good information for my algorithm
Basically, I'm trying to start out at 'S' for start and quit at 'F' for finish or return no solution message
the two self styled tests or text files being considered
##########
#S #
###### #
#F #
##########
and non-solvable
##########
#S #
##########
#F #
##########
My problem is I'm having trouble writing a pathfinding def for this and returning it to the custom print def. Below is the code for the whole darn thing. As well as my first attempt at it. Spaces are free to be a path. Walls are defined as any other key but the space bar. Also be warned my while loop for quiting will return an error, I'm working that out right now.
puts "enter a file name (example maze1.mz) PRESS ENTER"
filename = gets.chomp.to_s
while filename != 'quit' do
def read_maze( filename )
local_maze = []
mz_file = File.open(filename,"r")
while ! mz_file.eof? do
line = mz_file.gets.chomp
local_maze << line.scan(/./)
end
mz_file.close
return local_maze
end
def solve_maze(row, column, blank_spot, blank_spot_not ) #parse throug args
#from http://en.wikipedia.org/wiki/Maze
#from http://en.wikipedia.org/wiki/Pathfinding
return unless self[column][row] #condition for its full
return if self[column][row] != space #condition for printable spot
return if self[column][row] == blank_spot_not #can't use this spot
return if self[column][row]== full or f encountered
#maze is full can't solve or finished
self[column][row] = blank_spot_not
#direction up down left right
solve_maze(column+1, row, space, blank_spot_not) #right
solve_maze(column-1, row, space, blank_spot_not) #left
solve_maze(column, row+1, space, blank_spot_not) #up
solve_maze(column, row-1, space, blank_spot_not) #down
end
def print_maze( maze )
maze.each {|row|
puts row.join('')
}
end
maze = read_maze(filename)
print_maze(maze)
solve_maze(maze)
print_maze(maze)
puts "would you like to further drive yourself nuts with this maze solver"
filename = gets.chomp.to_s
maze = read_maze(filename)
print_maze(maze)
end
puts "you have quit"
Here's a couple of hints regarding your code:
solve_maze takes four parameters, but you are only passing one in the initial invocation (solve_maze(maze))
All your objects are either strings or arrays of strings, but you are constantly doing integer math with them
You are constantly using self to refer to the current object, but you don't even have a current object, since you are writing in a procedural style, not an object-oriented one. [Note: I know that in Ruby, you always have a current object, which in this case is the anonymous top-level object.]
Here's a couple of more hints regarding your workflow:
Forget about the while loop. Why would you want the possibility of solving multiple mazes when you cannot even solve one at the momen? You can always add that in later.
Forget about reading the maze from a file, just hardcode it in a string. You can always add that in later.
In fact, forget about parsing the string altogether, just hardcode the maze in a datastructure that is convenient for you to deal with. I'd suggest a two-dimensional array of Booleans. You can always ... well, you get the drift.
Start with a simple maze. Like, really simple. Like, one tile where you already start up at the destination. Then move on to a maze with two tiles where the destination is right next to the start.
Examples:
solvable = [
[false, false, false, false, false, false, false, false, false, false],
[false, true, true, true, true, true, true, true, true, false],
[false, false, false, false, false, false, true, true, true, false],
[false, true, true, true, true, true, true, true, true, false],
[false, false, false, false, false, false, false, false, false, false]
]
unsolvable = [
[false, false, false, false, false, false, false, false, false, false],
[false, true, true, true, true, true, true, true, true, false],
[false, false, false, false, false, false, false, false, false, false],
[false, true, true, true, true, true, true, true, true, false],
[false, false, false, false, false, false, false, false, false, false]
]
start = [1, 1]
finish = [3, 1]
This way, you can simply use if to check whether the path is free or not, since empty tiles are true and walls are false
Here's a neat trick: in Ruby, everything which is not either false or nil is true. This means, you can put everything you want (except false or nil, of course) in there instead of true and the if trick will still work. For example, you can encode the distance information that the algorithm needs directly in the maze itself. Just put some really big number instead of true in there, and 0 into the finish:
infin = 1.0/0.0
solvable = [
[false, false, false, false, false, false, false, false, false, false],
[false, infin, infin, infin, infin, infin, infin, infin, infin, false],
[false, false, false, false, false, false, infin, infin, infin, false],
[false, 0 , infin, infin, infin, infin, infin, infin, infin, false],
[false, false, false, false, false, false, false, false, false, false]
]
unsolvable = [
[false, false, false, false, false, false, false, false, false, false],
[false, infin, infin, infin, infin, infin, infin, infin, infin, false],
[false, false, false, false, false, false, false, false, false, false],
[false, 0 , infin, infin, infin, infin, infin, infin, infin, false],
[false, false, false, false, false, false, false, false, false, false]
]
start = [1, 1]
finish = [3, 1]
However, start simple:
maze = [[0]]
start = [0, 0]
finish = [0, 0]
maze = [[0, infin]]
start = [0, 1]
finish = [0, 0]
maze = [
[false, false, false],
[false, infin, false],
[false, 0 , false],
[false, false, false]
]
start = [1, 1]
finish = [2, 1]
maze = [
[false, false, false],
[false, infin, false],
[false, infin, false],
[false, 0 , false],
[false, false, false]
]
start = [1, 1]
finish = [3, 1]

Resources