Creating and adding to arrays within a program -- Ruby - ruby

I'm a fairly new Ruby user and I was wondering how you create and edit arrays within a program. I'm making a sentence-generator-type program where you can add to arrays of nouns, verbs, and other sentence parts, but I'm currently not sure how to make the arrays in the first place.
Here's the code:
#!/usr/bin/ruby Make_a_Sentence!
#This will eventually create the sentence
def makeSent (*arg)
for i in 0...arg.length
print arg[i].sample if arg[i].kind_of?(Array)
print arg[i] if arg[i].kind_of?(String)
end
end
#this is supposed to add to the array (it's not working)
def addWord (array, word)
if array.kind_of?(Array)
array.push(word)
puts "#{ word } added to #{ array }"
else
puts "#{ array } does not exist"
end
end
#This is supposed to create the arrays
def addType (name)
#name = Array.new
puts "#{ name } created"
end
while 1 > 0
input = gets
$words = input.split
if $words[0] == "addWord" && $words.length == 3
addWord($words[1], $words[2])
end
if $words[0] == "addType" && $words.length == 2
addType($words[1])
end
end
**Sorry! I guess I didn't phrase the question well enough! I was mainly wondering how to create new arrays while the program is running, but the arrays have specific names that are given. I actually ended up just using hashes for this, but thanks for the responses nonetheless!

Making an Array is done like so:
array = ["val1","val2","val3"]
array = %w{value value value}
# The second example is a shorthand syntax (splits values with just a space)
Familiarize yourself with the documentation: http://www.ruby-doc.org/core-2.1.0/Array.html
Also when you're using methods like: def makeSent (*arg) just be aware that *args with the * in front of it - is what's called a splat. Which means this method takes many arguments without the [] syntax and automatically converts all of the arguments into an array for you.
So you would call this method like: makeSent (first, second, third, etc)

Creating arrays is easy: simply enclose the objects in square brackets, like so:
my_array = [12, 29, 36, 42]
another_array = ['something', 64, 'another', 1921]
Notice you can mix and match types within the array. If you want to add items to the end of the array, you can use << to do it:
my_array = [1, 3, 5, 7]
my_array << 9
# my_array is now: [1, 3, 5, 7, 9]
You can access and modify specific items within the array by indexing it within square brackets:
my_array[2] # <-- this will be 5, as arrays are 0-indexed
my_array[2] = 987
# my_array is now [1, 3, 987, 7, 9]
There are a lot of great methods for accessing, modifying, and comparing arrays that you can find in the documentation.

Related

How can I get different behaviour from class to_s method for string interpolation syntax?

I've written a class that is acting like an array for another class. I have a to_s method which returns in a similar manner to an array when used as follows:
array = [1, 2, 3, 4]
puts array
This results in the output:
1
2
3
4
When used with string interpolation puts "#{array}" the output is different:
[1, 2, 3, 4]
How can I implement a to_s method in my class to provide both a multiline output for when it is not used in string interpolation and a single line output when it is?
I considered trying to get the caller label with caller_locations(1,1)[0].label but this seems far from optimal. Any help or direction to the relevant documentation would be much appreciated, I haven't been able to find anything on the subject yet. Thanks!
Array#to_s does not (and should not) inspect the context it is called in. The array is printed differently, because puts checks if the given argument is an array (or can be converted to an array). From the documentation:
If called with an array argument, writes each element on a new line.
You can provide a to_ary method:
class MyArray
def to_s
[1, 2, 3].join('-')
end
def to_ary
[1, 2, 3]
end
end
a = MyArray.new
puts a # calls to_ary and then prints each item on a separate line
# 1
# 2
# 3
puts a.to_s # just prints the result of to_s
# 1-2-3
puts "#{a}" # same as above
# 1-2-3

How to display an array with ruby nested each?

Given a list of array, I want to display all pair combination of the array in the form of array of two. For example, let's say I have an array of [1,2,3].
[1, 1]
[1, 2]
[1, 3]
[2, 1]
[2, 2]
[2, 3]
[3, 1]
[3, 2]
[3, 3]
Expected result
This is the function I came up with:
def all_combination(list)
list.each do |i|
list.each do |j|
puts [i,j]
end
end
end
arr1 = [1,2,3] #arr1 can be an array of any size. It will always be integer.
all_combination(arr1)
However, when I do the above code, it displays
1
1
1
2
1
3
...
It seems like there is a gap in my fundamental ruby knowledge. Why puts [i,j] does not work? How can I make it display an actual array like it shows on Expected result section?
I can make it work with puts "#{i}, #{j}", but it does not return an array pair [a,b]
There's a builtin method for what you want:
[1,2,3].permutation(2).each {|a| p a}
If you prefer to stick with your own method (to get "pairs" of items with themselves), change puts [i,j] to either p [i,j] or to puts [i,j].to_s— puts works with strings.
The reason you get the data on each new line is because puts writes each object given to it on a new line. Here is the doc on this:
Writes the given objects to ios as with IO#print. Writes a record
separator (typically a newline) after any that do not already end with
a newline sequence. If called with an array argument, writes each
element on a new line. If called without arguments, outputs a single
record separator.
If Array#permutation does what you want than that is the way to go, however, I don't think it matches what you asked for (ie [1,1],[2,2],[3,3] will not be included).
The following should provide you with what you were originally asking for.
def all_combination(list)
a = []
list.each do |i|
list.each do |j|
a << [i,j]
end
end
a
end
x = all_combination [1,2,3]
p x
puts x
=> [[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]]
1
1
1
2
1
3
2
1
2
2
2
3
3
1
3
2
3
3
x is the returned value you were looking for as shown by p x
ps: this could probably be done with a line or too less using Array#reduce, but this is fairly strait forward.
It seems like there is a gap in my fundamental ruby knowledge. Why puts [i,j] does not work?
Why don't we just look at the documentation?
The documentation for Kernel#puts simply refers us to the documentation for IO#puts:
puts(obj, …) → nil
Equivalent to
$stdout.puts(obj, …)
The documentation for IO#puts says this (bold emphasis mine):
puts(obj, …) → nil
Writes the given objects to ios as with IO#print. Writes a record separator (typically a newline) after any that do not already end with a newline sequence. If called with an array argument, writes each element on a new line. If called without arguments, outputs a single record separator.
As you can see, the documentation clearly states that when you pass an Array to puts, it will print each element on a separate line.
How can I make it display an actual array like it shows on Expected result section?
You cannot display an "actual array". An array is a data structure that maps indices to objects. It's an idea. You cannot display an idea. You can only display text (i.e. a String). So, you need to construct a String that looks like your desired output.
I can make it work with puts "#{i}, #{j}", but it does not return an array pair [a,b]
Well, it doesn't print the brackets because you didn't tell it to print brackets. It will simply print your String, but there aren't any brackets in your String, ergo there won't be brackets in the output. You just have to add them:
puts "[#{i}, #{j}]"
Note: you may be tempted to use Array#inspect, Array#to_s, or Kernel#p, but please don't: their output format is not guaranteed. You may get what you expect, but then again, you may not.
#inspect is for human-readable debugging output. Kernel#p simply calls #inspect. In the particular case of Array#to_s, it is simply an alias for Array#inspect, and the documentation only says:
inspect → string
to_s → string
Creates a string representation of self.
[ "a", "b", "c" ].to_s #=> "[\"a\", \"b\", \"c\"]"
Note that it only says "a string representation", but does not guarantee what string representation it returns.
The way I would approach your problem is something like this:
def all_combination(list)
list.product(list).map {|a, b| "[#{a}, #{b}]" }
end
arr1 = [1,2,3]
puts all_combination(arr1)
I mainly did two things:
Use higher-level collection operations already provided by the Ruby core library (Array#product and Enumerable#map). This reduces the cognitive overhead of understanding the solution. It's now just one line that clearly tells you what it does: first generate the cartesian product of the list with itself, then transform each pair to a suitable string representation.
Separate construction of the output from printing the output. This makes it easier to test: you can simply assert that returns the correct value, instead of having it print directly to the screen, and then jumping through hoops to capture the screen output and compare it to some pre-recorded screen output or something like that.
There are still things to improve, though:
the method does two things: generating the cartesian product and transform it to a string representation
the method naming: this actually hints at #1 above: how can you find a suitable name that describes precisely what a method does, when the method does multiple things at once?

Class variable returns empty after first run through a function

I am writing a mastermind game in Ruby. So far I have the code located here on github.
The problem I am running into is this: when I run the function below, the instance variable #code which is generated at the beginning of the game returns empty after the first run of the function.
I have assigned a local variable, tempcode, the value of #code, and all the operations are done to tempcode within the function. I have also assigned an attr_reader to #code, instead of an attr_accessor. So #code shouldn't change!
def compare_guess_to_code()
correct_color = "1"
correct_color_and_pos = "2"
incorrect_color = "0"
tempcode = #code
a = 0
#guess.length.times do #maybe a for loop that goes through both arrays simultaneously?
case
when #guess[a] == tempcode[a]
feedback.push(correct_color_and_pos)
tempcode.delete_at[a]
#guess.delete_at[a]
when guess[a] != tempcode[a] && tempcode.include?(guess[a])
feedback.push(correct_color)
tempcode.delete_at[a]
#guess.delete_at[a]
when !(tempcode.include?(guess[a]))
feedback.push(incorrect_color)
tempcode.delete_at[a]
#guess.delete_at[a]
else
puts "Error"
end
end
feedback.sort!
feedback.reverse!
print "Feedback: #{feedback}"
end
The feedback returns properly, everything seems to be working fine, I just can't do the comparison function more than one time before #code empties out. How can I hold the value consistent?
If you want to run the program to test it, use mastermind/lib/mastermind.rb.
You assign array tempcode = #code and modify it with tempcode.delete_at[a] which will change #code as well. To fix it, you can use
tempcode = #code.clone
This way #code won't be affected by tempcode's change
when you assign one array it just copies the reference and both of them point to the same reference.
so a change in one is reflected when you print either of them.
orig_array = [1,2,3,4]<br>
another_array = orig_array
puts orig_array.unshift(0).inspect
puts another_array.inspect
Output:
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]
To avoid this you can use Marshal to copy from original array without impacting the object to which it is copied.
Any changes in the original array will not change the object to which it is copied.
orig_array = [1,2,3,4]<br>
another_array = Marshal.load(Marshal.dump(orig_array))
puts orig_array.unshift(0).inspect
puts another_array.inspect
Output:
[0, 1, 2, 3, 4]
[1, 2, 3, 4]

Ruby Building an Array

Argh. Having trouble here trying to work out how to build my array in Ruby.
So I am looping through a result and I want to add the category field as the key and have it so that if the next row has the same category it gets put into that category. If not, it makes a new array and adds it to that.
Here is what I have so far.
data = Array.new
results.each do |row|
data[row.category].push row.field
end
Which is not going to work I know. I want data[row.category] to eventually be (after the loop) an array containing all the row.field's
So I end up with an array that looks like this.
[['Dogs', 5, 12, 2], ['Cats', 4, 5, 9], ['Fish', 25, 82, 23]]
So no matter how many loops I do, if I push it into an array that already exists in data then it just appends it, if the array doesn't exist it creates it and then appends it.
In PHP I would simply do this:
$data[$row['category']][] = $row['field']
With the empty [] denoting to create a new array if there is none. How do I do this in Ruby???
Yeah, you seem to be confused by PHP and its associative arrays (which aren't called arrays in any other language :) ). You need a hash. Try this snippet:
data = results.each_with_object({}) do |row, memo|
memo[row.category] ||= [] # create array unless it exists
memo[row.category] << row.field
end
Unlike PHP, you cannot use any object as index for an Array. In Ruby, we use Hashes to associate arbitrary objects with other objects.
Your code should work if you change it to:
data = Hash.new { |hash, key| hash[key] = [] }
results.each do |row|
data[row.category] << row.field
end

How can I get a lazy array in Ruby?

How can I get a lazy array in Ruby?
In Haskell, I can talk about [1..], which is an infinite list, lazily generated as needed. I can also do things like iterate (+2) 0, which applies whatever function I give it to generate a lazy list. In this case, it would give me all even numbers.
I'm sure I can do such things in Ruby, but can't seem to work out how.
With Ruby 1.9 you can use the Enumerator class. This is an example from the docs:
fib = Enumerator.new { |y|
a = b = 1
loop {
y << a
a, b = b, a + b
}
}
p fib.take(10) #=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Also, this is a nice trick:
Infinity = 1.0/0
range = 5..Infinity
p range.take(10) #=> [5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
This one only works for consecutive values though.
Recently Enumerable::Lazy has been added to ruby trunk. We'll see it in ruby 2.0.
In particular:
a = data.lazy.map(&:split).map(&:reverse)
will not be evaluated immediately.
The result is instance of Enumerable::Lazy, that can be lazy chained any further. If you want to get an actual result - use #to_a, #take(n) (#take is now lazy too, use #to_a or #force), etc.
If you want more on this topic and my C patch - see my blog post Ruby 2.0 Enumerable::Lazy
Lazy range (natural numbers):
Inf = 1.0/0.0
(1..Inf).take(3) #=> [1, 2, 3]
Lazy range (even numbers):
(0..Inf).step(2).take(5) #=> [0, 2, 4, 6, 8]
Note, you can also extend Enumerable with some methods to make working with lazy ranges (and so on) more convenient:
module Enumerable
def lazy_select
Enumerator.new do |yielder|
each do |obj|
yielder.yield(obj) if yield(obj)
end
end
end
end
# first 4 even numbers
(1..Inf).lazy_select { |v| v.even? }.take(4)
output:
[2, 4, 6, 8]
More info here:
http://banisterfiend.wordpress.com/2009/10/02/wtf-infinite-ranges-in-ruby/
There are also implementations of lazy_map, and lazy_select for the Enumeratorclass that can be found here:
http://www.michaelharrison.ws/weblog/?p=163
In Ruby 2.0.0, they were introduced new method "Lazy" in Enumerable class.
You can check the lazy function core and usage here..
http://www.ruby-doc.org/core-2.0/Enumerator/Lazy.html
https://github.com/yhara/enumerable-lazy
http://shugomaeda.blogspot.in/2012/03/enumerablelazy-and-its-benefits.html
As I already said in my comments, implementing such a thing as lazy arrays wouldn't be sensible.
Using Enumerable instead can work nicely in some situations, but differs from lazy lists in some points: methods like map and filter won't be evaluated lazily (so they won't work on infinite enumerables) and elements that have been calculated once aren't stored, so if you access an element twice, it's calculated twice.
If you want the exact behavior of haskell's lazy lists in ruby, there's a lazylist gem which implements lazy lists.
This will loop to infinity:
0.step{|i| puts i}
This will loop to infinity twice as fast:
0.step(nil, 2){|i| puts i}
This will go to infinity, only if you want it to (results in an Enumerator).
table_of_3 = 0.step(nil, 3)
I surprised no one answered this question appropriately yet
So, recently I found this method Enumerator.produce which in conjunction with .lazy does exactly what you described but in ruby-ish fashion
Examples
Enumerator.produce(0) do
_1 + 2
end.lazy
.map(&:to_r)
.take(1_000)
.inject(&:+)
# => (999000/1)
def fact(n)
= Enumerator.produce(1) do
_1 + 1
end.lazy
.take(n)
.inject(&:*)
fact 6 # => 720
The right answer has already identified the "lazy" method, but the example provided was not too useful. I will give a better example of when it is appropriate to use lazy with arrays. As stated, lazy is defined as an instance method of the module Enumerable, and it works on EITHER objects that implement Enumerable module (e.g. arrays - [].lazy) or enumerators which are the return value of iterators in the enumerable module (e.g. each_slice - [].each_slice(2).lazy). Note that in Enumerable module, some of the instance methods return more primitive values like true or false, some return collections like arrays and some return enumerators. Some return enumerators if a block is not given.
But for our example, the IO class also has an iterator each_line, which returns an enumerator and thus can be used with "lazy". The beautiful thing about returning an enumerator is that it does not actually load the collection (e.g. large array) in memory that it is working on. Rather, it has a pointer to the collection and then stories the algorithm (e.g. each_slice(2)) that it will use on that collection, when you want to process the collection with something like to_a, for example.
So if you are working with an enumerator for a huge performance boost, now you can attach lazy to the enumerator. So instead of iterating through an entire collection to match this condition:
file.each_line.select { |line| line.size == 5 }.first(5)
You can invoke lazy:
file.each_line.lazy.select { |line| line.size == 5 }.first(5)
If we're scanning a large text file for the first 5 matches, then once we find the 5 matches, there is no need to proceed the execution. Hence, the power of lazy with any type of enumerable object.
Ruby Arrays dynamically expand as needed. You can apply blocks to them to return things like even numbers.
array = []
array.size # => 0
array[0] # => nil
array[9999] # => nil
array << 1
array.size # => 1
array << 2 << 3 << 4
array.size # => 4
array = (0..9).to_a
array.select do |e|
e % 2 == 0
end
# => [0,2,4,6,8]
Does this help?

Resources