Ruby 1.9 bug? -- Array.permutation - ruby

While trying problem 41 from the Euler Project, I ran across what seems to be a bug in the Ruby 1.9 implementation of Array.permutation. Here's the problem code isolated:
n = 4
slice = '987654321'.chars.to_a[-n..-1]
puts "slice = #{slice.join}"
slice.permutation(n) {|perm| puts perm.join}
slice2 = slice.dup
puts "slice2 = #{slice2.join}"
slice2.permutation(n) {|perm| puts perm.join}
slice3 = []
(0...n).each {|i| slice3[i] = slice[i]}
puts "slice3 = #{slice3.join}"
slice3.permutation(n) {|perm| puts perm.join}
My output for slice and slice2 is:
slice = 4321
9876
9867
9786
9768
9687
...
However, slice3 comes out right, with the digits 1 to 4 being permuted. Also n = 4 is the first value that has this problem. When I set n = 3, I get the expected output. Is this a bug, or am I mis-coding something? A quick Google search didn't turn up anything.

It is a known bug which is fixed in 1.9.2p136 and newer.
Easiest way around it, besides updating to a more recent Ruby, is to insure your array is not "shared", either by building a new one (like your slice3), or simply "modifying" it, e.g. slice += [].

Related

Finding the sum,highest,lowest in a Hash/Array. Ruby

I am fairly new to this so I apologize in advance of my newbieness. I have been working on a project that I want to get the sum, highest,lowest out of a hash/array. I have tried numerous times to get this right but I typically will get an error such as, fixNum cannot convert int to string and undefined method. I will attempt to fix these issues and then run into another issue so I am at a loss. For the record in my text file I have 1,Foo,22 2,Smith,30 my output looks like this {1=>["Foo",22], 2=>["Smith",30]} I would like the highest number to show 30, lowest to be 22 and total to be 52 for different outputs.
You can do as below suppose lets say a variable a = {a: [a,1],b: [b,1] } then
values = a.values.map(&:last) //Gives the last element of each array
max= a.max
min = a.min
sum = a.sum
Okay, this is very ugly and someone will probably improve upon it but it works. Assuming I understand the output you would like.
elements = h.map{ |element| element[1] }.map { |element| element[1]}
# sum
elements.sum
# highest
elements.max
# lowest
elements.min
https://repl.it/repls/AntiqueOldfashionedRom
Convert to hash and calculate min max based on values
data = "1,Foo,22 2,Smith,30"
people =
data.split(",")
.each_slice(3)
.map {|slice| [slice[0], [slice[1], slice[2]]] }
.to_h
values = people.values.map {|person| person[1] }
min = values.min
max = values.max
sum = values.sum

Ruby: deleting object while looping over list with that object

So I have multiple lists to keep track of objects in a 2D game, but if these objects go off screen I want to remove these objects so they are no longer updated. What I have below works for me, but this doesn't work in other languages. Usually I have to make another "destroy list" that saves the objects I want to destroy and then loop again to remove them, because you can't remove an object from the list while iterating without some visible glitch.
Is Ruby just not showing any visible glitch while doing this or does Ruby's array work differently when removing multiple possible objects from a list while it's still iterating?
objects = []
objects.each{|o| o.withinBounds ? o.update : objects.delete(o)}
In Ruby you will actually find a glitch if you do what you are saying.
Try this:
objects = [1,2,3,4]
objects.each { |el| objects.delete(el) }
=> [2, 4]
You would expect the result to be an empty array, but is not. We are messing up with the elements of the arr and each gets confused, because the length of the array has changed. The each iterator looks something like this in pseudocode:
count = 0
while length(objects) > count
yield objects[count]
count + 1
end
So, in the example I shown above, the reason why we get [2, 4] can be explained on a step by step analysis on what objects.each { |el| objects.delete(el) } is doing:
We start with 4 (length of objects) > 0.
Number 1 is yielded, and deleted.
count = 1
3 (length of objects) > 1
Number 3 is yielded and deleted.
count = 2
2 (length of objects) is not bigger than count
We are done, so we have [2, 4]
There is a better way to do what you are trying, by using delete_if:
new_objects = objects.delete_if {|o| o.withinBounds }

Optimizing Array Memory Usage

I currently have a very large array of permutations, which is currently using a significant amount of RAM. This is the current code I have which SHOULD:
Count all but the occurrences where more than one '1' exists or three '2's exist in a row.
arr = [*1..3].repeated_permutation(30).to_a;
count = 0
arr.each do |x|
if not x.join('').include? '222' and x.count(1) < 2
count += 1
end
end
print count
So basically this results in a 24,360 element array, each of which have 30 elements.
I've tried to run it through Terminal but it literally ate through 14GB of RAM, and didn't move for 15 minutes, so I'm not sure whether the process froze while attempting to access more RAM or if it was still computing.
My question being: is there a faster way of doing this?
Thanks!
I am not sure what problem you try to solve. If your code is just an example for a more complex problem and you really need to check programatically every single permumation, then you might want to experiment with lazy:
[*1..3].repeated_permutation(30).lazy.each do ||
# your condition
end
Or you might want to make the nested iteratior very explicit:
[1,2,3].each do |x1|
[1,2,3].each do |x2|
[1,2,3].each do |x3|
# ...
[1,2,3].each do |x30|
permutation = [x1,x2,x3, ... , x30]
# your condition
end
end
end
end
end
But it feels wrong to me to solve this kind of problem with Ruby enumerables at all. Let's have a look at your strings:
111111111111111111111111111111
111111111111111111111111111112
111111111111111111111111111113
111111111111111111111111111121
111111111111111111111111111122
111111111111111111111111111123
111111111111111111111111111131
...
333333333333333333333333333323
333333333333333333333333333331
333333333333333333333333333332
333333333333333333333333333333
I suggest to just use enumerative combinatorics. Just look at the patterns and analyse (or count) how often your condition can be true. For example there are 28 indexes in your string at which a 222 substring could be place, only 27 for the 2222 substring... If you place a substring how likely is it that there is no 1 in the other parts of the string?
I think your problem is a mathematics problem, not a programming problem.
NB This is an incomplete answer, but I think the idea might give a push to the proper solution.
I can think of a following approach: let’s represent each permutation as a value in ternary number base, padded by zeroes:
1 = 000..00001
2 = 000..00002
3 = 000..00010
4 = 000..00011
5 = 000..00012
...
Now consider we restated the original task, treating zeroes as ones, ones as twos and twos as threes. So far so good.
The whole list of permutations would be represented by:
(1..3**30-1).map { |e| x = e.to_s(3).rjust(30, '0') }
Now we are to apply your conditions:
def do_calc permutation_count
(1..3**permutation_count-1).inject do |memo, e|
x = e.to_s(3).rjust(permutation_count, '0')
!x.include?('111') && x.count('0') < 2 ? memo + 1 : memo
end
Unfortunately, even for permutation_count == 20 it takes more than 5 minutes to calculate, so probably some additional steps are required. I will be thinking of further optimization. Currently I hope this will give you a hint to find the good approach yourself.

when and how to convert section of code to a method in ruby

I had a question regarding identifying all the points next to a given cell or set of cells) in a matrix (see Need a Ruby way to determine the elements of a matrix "touching" another element). Since no suitable ideas were put forth, I decided to proceed via brute force.
The code below successfully does what I sought to do. The array tmpl (template) contains a map of how to get from a given coordinate (provided by atlantis) to the 8 cells surrounding it. I then construct an array sl (shoreline) that contains all the “underwater” land touching the shoreline of atlantis by summing each element of atlantis with all elements of tmpl.
# create method to determine elements contiguous to atlantis
require 'matrix'
atlantis = [[2,3],[3,4]]
tmpl = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]
ln = 0
sl = []
while ln < atlantis.length
n = 0
tsl = []
while n < 8
tsl[n] = [atlantis[ln], tmpl[n]].transpose.map { |x| x.reduce(:+) }
n = n+ 1
end
sl = sl + tsl
ln = ln + 1
end
sl = sl - atlantis
sl.uniq!
sl.to_a.each { |r| puts r.inspect }
But I have a problem (one of many remaining) in that I still need 2 levels of loops above what’s shown here (one to keep adding land to atlantis until it reaches a set size and another to make additional islands, Bermuda, Catalina, etc.) and already this is becoming difficult to read and follow. My vague understanding of object oriented programming suggests that this cold be improved by turning some of these loops into methods. However, I learned to program 35 years ago in basic and am struggling to learn Ruby as it is. So my requests are:
Is in fact better to turn these into methods?
If so, would anyone be willing to show me how that’s done by changing something into an method?
What do you do when you add additional levels and discover you need to change something in a lower method as a result? (e.g, after figuring out the simple case of how to create sl with just one value in atlantis, I had to go back and rework it for longer values.)
I hoping by asking the question in this way, it becomes something also useful to other nubies.
BTW, this bit .transpose.map { |x| x.reduce(:+) } I found on Stack Overflow (after hours of trying to do it ‘cause it should be simple and if I couldn’t do it I must be missing something obvious. Yeah, I bet you know too.) lets you add two arrays element by element and I have no idea how it works.)
already this is becoming difficult to read and follow
One way of making it less difficult to read and follow is to try to make the code "self document", by using readable variable names and Ruby idioms to reduce the clutter.
A quick refactor of your code gives this:
require 'matrix'
atlantis = [[2,3],[3,4]]
template = [[-1,-1],[-1,0],[-1,1],[0,-1],[0,1],[1,-1],[1,0],[1,1]]
shoreline = []
atlantis.each do |atlantum|
shoreline += template.inject([]) do |memo, element|
memo << [atlantum, element].transpose.map { |x| x.reduce(:+) }
memo
end
end
shoreline = shoreline - atlantis
shoreline.uniq!
shoreline.each { |r| puts r.inspect }
The main processing block is half the size, and (hopefully) more readable, and from here you can use the extract method refactor to tidy it further if you still need/want to.

Odd Ruby Behaviour

Consider the following Ruby code:
a = ["x"] * 3 # or a = Array.new(3, "x")
a[0].insert(0, "a")
a.each {|i| puts i}
I would expect the output to be ax, x, x (on new lines of course). However, with Ruby 1.9.1 the output is ax, ax, ax. What's going on? I've narrowed the problem down to the way the array a is defined. If I explicitly write out
a = ["x", "x", "x"]
then the code works as expected, but either version in the original code gives me this unexpected behaviour. It appears that the */initializer means the copies are actually references to the same copy of the string "x". However, if instead of the insert command I write
a[0] = "a" + a[0]
Then I get the desired output. Is this a bug, or is there some feature at work which I'm not understanding?
The documentation to Array.new(size=0, obj=nil):
... it is created with size copies of obj (that is, size references to the same obj).
and Array * int:
... returns a new array built by concatenating the int copies of self
So in both of the forms you're surprised by, you end up with three references to the same "x" object, just as you figured out. I'd say you might argue about the design decision, but it's a documented intentional behavior, not a bug.
The best way I know to get the behavior you want without manually writing the array literal (["x", "x", "x"]) is
a = Array.new(3) {"x"}
Or course, with just three elements, it doesn't much matter, but with anything much bigger, this form comes in handy.
In short, although "x" is just a literal, it is an object. You use ["x'] * 3 so a is containing 3 same object. You insert 'a' to one of them, they will be all changed.

Resources