I have many multiple dimensional arrays. A simplified example:
t0 = [2, 1, 3, 2, 2, 2, 2, 1, 2, 3]
t1 = [1, 2, 1, 3, 2, 2, 2, 2, 1, 2]
t2 = [2, 1, 3, 2, 2, 2, 2, 1, 2, 3]
t3 = [2, 1, 1, 3, 1, 4, 2, 2, 1, 2]
t4 = [2, 1, 3, 1, 2, 2, 2, 2, 1, 2]
t = [t0,t1,t2,t3,t4]
instance1= [t]
Each cell is processed. For each cell the 8 ajoining cells (think terrain map) plus the equivalent cells in several other arrays are accessed and updated. For example:
for h in 1..3
for i in 1..8
if instance1[0][i][h] == 4 # burning
if instance1[0][i-1][h-1] > 0 && instance1[0][i-1][h-1] < 4
# check probability
probability = Fernandes1(moisturex[0][i-1][h-1], windspeed, temperature, fueltypex[0][i-1][h-1])
if probability > 0.5
instance2[0][i-1][h-1] = 4 # now burning
end
end
if instance1[0][i-1][h] > 1 && instance1[0][i-1][h] < 4
# check probability
...................................
I would like to perform this processing in a user defined function. I guess the alternative to globals is to pass all variables as function parameters but that would be very tedious and error prone - there being so many.
Is the best approach to declare the arrays as global?
$t0 = [2, 1, 3, 2, 2, 2, 2, 1, 2, 3]
$t1 = [1, 2, 1, 3, 2, 2, 2, 2, 1, 2]
$t2 = [2, 1, 3, 2, 2, 2, 2, 1, 2, 3]
$t3 = [2, 1, 1, 3, 1, 4, 2, 2, 1, 2]
$t4 = [2, 1, 3, 1, 2, 2, 2, 2, 1, 2]
$t = [$t0,$t1,$t2,$t3,$t4]
$instance1= [$t]
And as here, do I need to define all the sub arrays as globals or just the ones that I directly reference in the user defined function? Or by defining the outer array (i.e. $instance1) as global do the sub arrays become global?
Any guidance much appreciated
OK defining just the globals that are referenced seems to work fine (e.g. the outer array but not the sub-arrays. I guess the only overhead of Globals is sustained use of memory.
But I'm wondering if there is a more Rubiesque way to go.
Related
I have 2 arrays
asc = [0, 1, 2, 3, 4, 5]
dsc = [5, 4, 3, 2, 1, 0]
I want a new array that is results of multiplying each corresponding item in asc and dsc
I'm used to Clojure where I would just map
(map #(* %1 %2) asc dsc) ;=> (0 4 6 6 4 0)
Is their an equivalent in Ruby, what would be the idiomatic way to do this in Ruby?
I'm new to Ruby but it seems to have really nice concise solutions, so I assume I'm missing something.
Do I just write:
i = 0
res = []
while i < asc.length() do
res.append(asc[i] * dsc[i])
end
Use zip to combine each element with its corresponding in two element array and than map
asc.zip(dsc).map { |a, b| a * b }
=> [0, 4, 6, 6, 4, 0]
It appears that dsc ("descending") is derived from asc ("ascending"), in which case you could write:
asc.each_index.map { |i| asc[i] * asc[-i-1] }
#=> [0, 4, 6, 6, 4, 0]
You could also write:
[asc, dsc].transpose.map { |a,d| a*d }
#=> [0, 4, 6, 6, 4, 0]
or:
require 'matrix'
Matrix[asc].hadamard_product(Matrix[dsc]).to_a.first
#=> [0, 4, 6, 6, 4, 0]
See Matrix#hadamard_product.
Use map and with_index:
asc = [0, 1, 2, 3, 4, 5]
dsc = [5, 4, 3, 2, 1, 0]
res = asc.map.with_index{ |el, i| el * dsc[i] }
puts res.inspect
# [0, 4, 6, 6, 4, 0]
Alternatively, use each_index and map:
res = asc.each_index.map{ |i| asc[i] * dsc[i] }
You could also write like below:
asc = [0, 1, 2, 3, 4, 5]
dsc = [5, 4, 3, 2, 1, 0]
p asc.zip(dsc).collect{|z| z.inject(:*)}
[0, 4, 6, 6, 4, 0]
I am trying to find the common elements in two arrays.
pairs = Array.new
a = exchange_one.get_symbols
b = exchange_two.get_symbols
c = a+b
c.uniq{|pair| pairs << pair}
I am combining the two arrays using +
Then I am calling uniq to remove the duplicate, but passing it to a block so the found duplicates can be added to an array before they are deleted.
For some reason the array pairs is just the entire c array.
What is the correct way to find array similarities.
If your goal is simply to determine which elements are the same between two arrays, you can use the intersection operator Array#&.
a = exchange_one.get_symbols
b = exchange_two.get_symbols
intersection = a & b
First understand what are you doing and what you want.
For eg.
a = 15.times.map { rand 6 }
#=> [1, 0, 5, 3, 1, 3, 4, 1, 3, 2, 1, 2, 4, 2, 3]
b = 15.times.map { rand 6 }
#=> [3, 3, 3, 1, 3, 1, 3, 1, 5, 1, 4, 2, 0, 0, 4]
Now what are you doing
c = a + b
#=> [1, 0, 5, 3, 1, 3, 4, 1, 3, 2, 1, 2, 4, 2, 3, 3, 3, 3, 1, 3, 1, 3, 1, 5, 1, 4, 2, 0, 0, 4]
c - only combine arrays irrespective of content hence get all values.
Now
pairs = Array.new
c.uniq{|pair| pairs << pair}
Here uniq is just act as a iterator means if you check 'pair' then it iterate all the values of 'c' and insert those values in 'pairs' array.
check this
c.uniq{|pair| puts pair}
Thats why you are getting all values within 'pairs' array.
The best way to find similarity in arrays is (a&b), but you can make changes in your code as follow to achieve it.
pairs = (arr1+arr2).uniq
OR
pairs = arr1 & arr2 #best and efficient way.
Suppose:
arr1 = 15.times.map { rand 6 }
#=> [1, 0, 4, 0, 2, 3, 1, 0, 2, 4, 4, 1, 3, 1, 1]
arr2 = 15.times.map { rand 6 }
#=> [5, 5, 4, 1, 5, 1, 5, 0, 4, 0, 2, 0, 4, 5, 0]
arr1 contains 5 1s and arr2 contains 2 1s. If, by "common elements" you wish to report that both arrays contain [5, 2].min #=> 2 1s, and similar counts for the other elements that appear in either array, you can do the following:
h1 = count(arr1)
#=> {1=>5, 0=>3, 4=>3, 2=>2, 3=>2}
h2 = count(arr2)
#=> {5=>5, 4=>3, 1=>2, 0=>4, 2=>1}
(h1.keys | h2.keys).each_with_object({}) { |k,h| h[k] = [h1[k], h2[k]].min }
#=> {1=>2, 0=>3, 4=>3, 2=>1, 3=>0, 5=>0}
def count(arr)
arr.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 }
end
I have a problem with Array.count method on a two-dimensional array.
I load my two-dimensional array from have a file where I have stored before, something like this:
[[1, 1, 1, 1, 1, 2, 2, 1, 1, 1], [1, 1, 1, 1, 1, 2, 2, 1, 1, 1], [1, 1, 1, 1, 1, 2, 2, 1, 1, 1], [1, 1, 1, 1, 1, 2, 2, 1, 1, 1], [1, 1, 1, 1, 1, 2, 2, 1, 1, 1], [1, 1, 1, 1, 1, 2, 2, 1, 1, 1], [1, 4, 4, 5, 1, 2, 2, 1, 1, 1], [1, 4, 4, 5, 1, 2, 2, 1, 1, 1], [1, 4, 4, 1, 2, 2, 1, 1, 1, 1], [1, 4, 4, 1, 0, 0, 1, 1, 1, 1]]
I made this class called Maps:
require 'json'
class Maps
def initialize(filename)
#map = JSON.parse(File.read(filename))
end
def isCorrupted?
#map.count(0) > 1 ? true : false
end
end
and when I try to use my class method isCorrupted? the result it's always false.
require_relative 'classes/maps'
current_map = Maps.new("test.txt")
puts current_map.isCorrupted?
I don't understand why the method doesn't find the two 0 in the ten sub-array and return FALSE.
I also try to modify the method to get the count occurrences, like this:
#map.count(0)
but the result it's always 0.
Can someone help me? I need to know the total number of ZERO in the global array.
Edit-2: Flatten was what I need.
Using flatten does not work here.
Doing so would be a valid optimisation, if the requirement was simply to check whether any 0 is present in the nested arrays. But that's not what you're doing here; you want to check that more than one 0 appears in any array.
For example, you want to consider the following as non-corrupt, but poashin's answer would consider it as corrupt:
[[0, 1], [1, 0]]
Therefore, you should iterate through the arrays:
require 'json'
class Maps
def initialize(filename)
#map = JSON.parse(File.read(filename))
end
def is_corrupted?
#map.any? { |row| row.count(0) > 1 }
end
end
(Minor point: I have followed the ruby style guide conventions here, and used snake_case for the method name, not camelCase.)
Now your code doesn't work the way you intend it to cause you are trying to count 0 elements in the collection of arrays (not integers).
In case you need to know if there are more than two zeroes in all subarrays in total:
#map.flatten.count(0) > 1
In case you want to know if there are subarrays that include one or more zeroes you should use another approach:
#map.any? { |collection| collection.count(0) > 1 }
I want to sort duplicate values from an array like below:
Array = [1, 2, 3, 5, 1, 2, 3, 1, 2, 1]
I want an output like below:
[1,1,1,1,2,2,2,3,3,5]
Sort duplicate values from an array.
Returns a new array created by sort. Comparisons for the sort will be done using the <=> operator.
Array = [1, 2, 3, 5, 1, 2, 3, 1, 2, 1]
Array.sort
# => [1, 1, 1, 1, 2, 2, 2, 3, 3, 5]
You can use Array.sort! as well.
Imagine one has an array such as:
a = [0, 1, 2, 3, 4, 2, 5, 1, 7, 6, 4, 5]
And one wishes to create an array consisting of the first n elements, starting with the first element in the array, that are a monotonic sequence increasing by one. Given a above, that array would be [0, 1, 2, 3, 4].
One could use slice_when, such as:
a.slice_when { |a, b| a != b - 1 }.first
The drawback of this approach is that slice_when continues to iterate over the array elements 2, 5, 1, and so on, until the end. In this case, iterating over the remaining values is useless, since one really just wants the first slice.
What is the elegant way to express this in Ruby, that ceases iterating once the first increasing sequence is selected?
How about lazy evaluation?
a = [0, 1, 2, 3, 4, 2, 5, 1, 7, 6, 4, 5]
a.lazy.slice_when { |a, b| a != b - 1 }.first
=> [0, 1, 2, 3, 4]
Enumerable#lazy
You could write the following.
def stairstep(arr)
return [] if arr.empty?
enum = arr.first.step
arr.take_while { |x| x == enum.next }
end
stairstep [1, 2, 3, 4, 6, 5, 1, 7, 6, 4, 5]
#=> [1, 2, 3, 4]
Perhaps something like this:
a = [0, 1, 2, 3, 4, 2, 5, 1, 7, 6, 4, 5]
(a.size - 1).times { |i| break a[0..i] if a[i] > a[i + 1] }
#=> [0,1,2,3,4]