Looping through sections of an array in Ruby - ruby

I have an array containing a large number of contents
Names = ["one", "two", ......."forty"]
Now, I would like to loop through sections of the array. For example, from records 10 to 20, How can I go about this?
I tried this approach -
Names.each_with_index do |val,index|
break if index == 10
puts "#{val}"
end
In this way, I can print the first ten records. What should I do for getting next set of 10 names?
Any help is appreciated.
Cheers!

You can use each_slice to get successive sections of the array. For example:
require 'enumerator'
Names.each_slice(10) do |slice|
slice.each do |x|
puts x
end
puts "----"
end

You can e.g. use the each_slice method:
Names.each_slice(10) {|part|
puts part
}

Related

Program to take input from command line into an array and find the biggest among them

I am new to Ruby and just can't figure out how you take input for an array from a user and display it.If anyone could clear that I can add my logic to find the biggest number.
#!/usr/bin/ruby
puts "Enter the size of the array"
n = gets.chomp.to_i
puts "enter the array elements"
variable1=Array.new(n)
for i in (0..n)
variable1[i]=gets.chomp.to_i
end
for i in (0..n)
puts variable1
end
How about capturing the array in one line?
#!/usr/bin/ruby
puts "Enter a list of numbers"
list = gets # Input something like "1 2 3 4" or "3, 5, 6, 1"
max = list.split.map(&:to_i).max
puts "The largest number is: #{max}"
You are doing it ok. But try this little change
#!/usr/bin/ruby
puts "Enter the size of the array"
n = (gets.chomp.to_i - 1)
puts "enter the array elements"
variable1=Array.new(n)
for i in (0..n)
variable1[i]=gets.chomp.to_i
end
puts variable1
or for undefined number of values here is one way
#!/usr/bin/ruby
puts "enter the array elements (type 'done' to get out)"
input = gets.chomp
arr = []
while input != 'done'
arr << input.to_i
input = gets.chomp
end
puts arr
I believe that this is a little bit more elegant solution.
puts "Please enter numbers separated by spaces:"
s = gets
a = s.split(" ")
#Displays array
puts a
#Displays max element
puts a.max
First you collect the series of numbers from the user, then you use a split method on the string, which converts it to the array. If you want to use some other separator, like "," than you can write s.split(","). After that you can use your logic to find the biggest number or you could just use max method.
Some feedback:
chomp.to_i is a bit redundant, since the latter will also remove newlines.
for x in y is not commonly seen in idiomatic Ruby code. It basically behaves like each with slightly different scoping rules and probably should have been removed from the language a while ago.
Ruby arrays are dynamic, so no need to preinitialize them. Something like (1..n).map { gets.to_i } would also produce the array you need.
Displaying it can then be done like this: array.each { |n| puts n }
Alternatively you can use the strip approach outlined before, take the numbers as command line arguments in ARGV or pipe into your program using ARGF.

Usage of Pipes in Ruby Loops

So, maybe I'm over-complicating something that isn't that hard, but here goes.
In Ruby, there's a method of looping called .each. I think that this is very cool--but what I'm finding less cool is the amount of stuff written about the pipe that comes after it (or any other do-type loop in Ruby, it would seem). Sometimes there is a single thing in the pipe:
basket.each do |fruit|
puts "This is a #{fruit}.\n"
end
But sometimes, there are two things in this pipe, like so:
contacts.each do |name, profession|
puts "#{name} is a #{profession}.\n"
end
So what I'm wondering now, is it possible to have more than two items in that pipe? Like if I have a huge, big, and ugly multi-dim array?
What if I add things to my pipe and they're not there? Will it give the value in the pipe nil? Or will it throw an error?
Again, sorry if this is obvious to long-time Rubyists, but I came from the land of strictly typed variables, and I'm now leaving PHP land, too. :)
EDIT
So what if I have something like this:
categories = [["Bathroom", "Bathroom Fixtures", "Plumbing"],
["Ceiling Fixtures", "Chandeliers", "Flush Mounts", "Mini Chandeliers", "Semi-Flush Mounts", "Pendants", "Track Lighting", "Mini Pendants", "Directional", "Island/Pool Table", "Recessed Lighting"],
["Outdoor", "Exterior", "Landscape Lighting"],
["Fans", "Fans", "Fan Accessories"],
["Lamps", "Lamps", "Shades"],
["Wall Fixtures", "Sconces", "Foyer/Hall Lanterns"],
["Specialty", "Undercabinet", "Light Bulbs", "Lighting Controls", "Glass", "Specialty Items", "Utility"],
["Home Decor", "Decor/Home Accents", "Furniture"]]
Can I loop through it like this?
categories.each do |category, subcats|
puts "The main category is #{category} and the sub categories are: "
subcats.each do |subcat|
puts "#{subcat}, "
end
end
Lets start with a break down of the each method.
a = [1,2,3,4,5]
a.each do |num|
puts num
end
# 1
# 2
# 3
# 4
# 5
The do ... end portion is called a block
This block accepts one parameter (an element in the array)
The way you pass parameters to a block is with |'s
If you supply more than one argument to the block:
a.each do |num, x|
puts num
puts x
end
# 1
#
# 2
#
# 3
#
# 4
#
# 5
#
x is nil for each iteration.
Lets write a method of our own that uses blocks so you can see how they work.
def my_each(a=[])
a.each do |x|
yield x if block_given?
end
end
my_each(a) do |num|
puts num
end
Here yield x is saying, execute the supplied block and pass x to it.
If you pass another parameter to your block, it is nil. Why?
Our implementation of my_each doesn't know anything about a second parameter so it does not yield anything so it remains nil.
When you have a simple array, the following things happen:
arr = [1,2,3,4]
arr.each do |x|
p x
end
1
2
3
4
=> [1,2,3,4]
arr.each do |x,y|
p x
p y
end
1
nil
2
nil
3
nil
4
nil
=> [1,2,3,4]
so if ruby doesn't know what to put into the block argument, it simply sets it to nil. Now consider a nested array:
arr = [[1,2],[3,4],[5,6]]
arr.each do |x|
p x
end
[1, 2]
[3, 4]
[5, 6]
=> [[1,2],[3,4],[5,6]]
arr.each do |x,y|
p x
p y
end
1
2
3
4
5
6
=> [[1,2],[3,4],[5,6]]
In this case, ruby assumes that you want to assign the two elements of the inner arrays to the block variables x and y. The same thing applies to hashes, where Ruby assigns the key and value to x and y:
hash = {1 => 2, 3 => 4, 5 => 6}
hash.each do |x,y|
p x
p y
end
1
2
3
4
5
6
=> {1=>2,3=>4,5=>6}
When you don't have enough elements in the nested arrays, the block variables are assigned nil, indeed. When there are too many of them, they are simply discarded:
arr = [[1,2,3],[4,5],[6]]
arr.each do |x,y|
p x
p y
end
1
2
4
5
6
nil
=> [[1,2,3],[4,5],[6]]
pretty straightforward!
EDIT:
As for your edited question: no, you cannot apply this 1:1 to Ruby code, you would have to manually apply the splat operator (*) to subcats. This way, ruby assigns all remaining elements to the 'splatted' block variable:
categories.each do |category,*subcats|
puts "The main category is #{category} and the sub categories are: "
subcats.each do |subcat|
puts "#{subcat}, "
end
end
although i would generate a comma-separated list of subcategories like this:
categories.each do |category,*subcats|
puts "The main category is #{category} and the sub categories are: "
puts subcats.join(', ')
end
EDIT 2:
Oh, and you would not handle a huge ugly evil multidimensional array by defining a lot of block parameters for its elements. You probably would iterate through it using nested loops as in almost every other language, if only because you never know how many elements it contains.
The pipes you are talking about is a parameter list of a block "variable". Actually that is some kind of a function pointer, and the pipes marks the parameter list.
Check the description of array.each.
This is not magic, the number of parameters is defined in the block, you can't add more than that, if you do, they won't get a value. The reason is for "sometime" there can be more than one, is that it's probably a hash.each, which has two parameters, a key and a value.
You can create your own functions with block parameters, read this.
For your iteration problem, you can use a hash, or you can write your own iterator.
Multiple Arguments to a Block
Array#each iterates over an array object, and passes either a single object into the block or returns an enumerator. You can redefine this behavior, but #each is the wrong method if you want multiple values at a time; see Enumerator#each_slice for an alternative.
Data Structures
Your problem would be easier to solve with the right data structure. Instead of an array, you should consider using a hash. For example:
categories =
{"Bathroom"=>["Bathroom Fixtures", "Plumbing"],
"Ceiling Fixtures"=>["Chandeliers", "Flush Mounts", "Mini Chandeliers"]}
categories.each do |key, value|
puts "#{key}:"
value.each { |v| puts "\t%s" % v }
end
This returns:
Bathroom:
Bathroom Fixtures
Plumbing
Ceiling Fixtures:
Chandeliers
Flush Mounts
Mini Chandeliers

Getting random element from ruby array (your solution)?

what is your version to this problem ?
i'm doing so:
array = [1,2,3,4,5,6,7,8,9]
puts array.sort_by { array }.first
puts array[rand(array.size)]
puts array.shuffle.first
puts array.sample
I use array.sample. It is MUCH easier to read than the first 2 and slightly easier to read than the third.

Syntax for a for loop in ruby

How do I do this type of for loop in Ruby?
for(int i=0; i<array.length; i++) {
}
array.each do |element|
element.do_stuff
end
or
for element in array do
element.do_stuff
end
If you need index, you can use this:
array.each_with_index do |element,index|
element.do_stuff(index)
end
limit = array.length;
for counter in 0..limit
--- make some actions ---
end
the other way to do that is the following
3.times do |n|
puts n;
end
thats will print 0, 1, 2, so could be used like array iterator also
Think that variant better fit to the author's needs
I keep hitting this as a top link for google "ruby for loop", so I wanted to add a solution for loops where the step wasn't simply '1'. For these cases, you can use the 'step' method that exists on Numerics and Date objects. I think this is a close approximation for a 'for' loop.
start = Date.new(2013,06,30)
stop = Date.new(2011,06,30)
# step back in time over two years, one week at a time
start.step(stop, -7).each do |d|
puts d
end
The equivalence would be
for i in (0...array.size)
end
or
(0...array.size).each do |i|
end
or
i = 0
while i < array.size do
array[i]
i = i + 1 # where you may freely set i to any value
end
array.each_index do |i|
...
end
It's not very Rubyish, but it's the best way to do the for loop from question in Ruby
To iterate a loop a fixed number of times, try:
n.times do
#Something to be done n times
end
If you don't need to access your array, (just a simple for loop) you can use upto or each :
Upto:
2.upto(4) {|i| puts i}
2
3
4
Each:
(2..4).each {|i| puts i}
2
3
4
What? From 2010 and nobody mentioned Ruby has a fine for /in loop (it's just nobody uses it):
ar = [1,2,3,4,5,6]
for item in ar
puts item
end
['foo', 'bar', 'baz'].each_with_index {|j, i| puts "#{i} #{j}"}
Ruby's enumeration loop syntax is different:
collection.each do |item|
...
end
This reads as "a call to the 'each' method of the array object instance 'collection' that takes block with 'blockargument' as argument". The block syntax in Ruby is 'do ... end' or '{ ... }' for single line statements.
The block argument '|item|' is optional but if provided, the first argument automatically represents the looped enumerated item.

Automatic counter in Ruby for each?

I want to use a for-each and a counter:
i=0
for blah in blahs
puts i.to_s + " " + blah
i+=1
end
Is there a better way to do it?
Note: I don't know if blahs is an array or a hash, but having to do blahs[i] wouldn't make it much sexier. Also I'd like to know how to write i++ in Ruby.
Technically, Matt's and Squeegy's answer came in first, but I'm giving best answer to paradoja so spread around the points a bit on SO. Also his answer had the note about versions, which is still relevant (as long as my Ubuntu 8.04 is using Ruby 1.8.6).
Should've used puts "#{i} #{blah}" which is a lot more succinct.
As people have said, you can use
each_with_index
but if you want indices with an iterator different to "each" (for example, if you want to map with an index or something like that) you can concatenate enumerators with the each_with_index method, or simply use with_index:
blahs.each_with_index.map { |blah, index| something(blah, index)}
blahs.map.with_index { |blah, index| something(blah, index) }
This is something you can do from ruby 1.8.7 and 1.9.
[:a, :b, :c].each_with_index do |item, i|
puts "index: #{i}, item: #{item}"
end
You can't do this with for. I usually like the more declarative call to each personally anyway. Partly because its easy to transition to other forms when you hits the limit of the for syntax.
Yes, it's collection.each to do loops, and then each_with_index to get the index.
You probably ought to read a Ruby book because this is fundamental Ruby and if you don't know it, you're going to be in big trouble (try: http://poignantguide.net/ruby/).
Taken from the Ruby source code:
hash = Hash.new
%w(cat dog wombat).each_with_index {|item, index|
hash[item] = index
}
hash #=> {"cat"=>0, "wombat"=>2, "dog"=>1}
If you don't have the new version of each_with_index, you can use the zip method to pair indexes with elements:
blahs = %w{one two three four five}
puts (1..blahs.length).zip(blahs).map{|pair|'%s %s' % pair}
which produces:
1 one
2 two
3 three
4 four
5 five
As to your question about doing i++, well, you cannot do that in Ruby. The i += 1 statement you had is exactly how you're supposed to do it.
If you want to get index of ruby for each, then you can use
.each_with_index
Here is an example to show how .each_with_index works:
range = ('a'..'z').to_a
length = range.length - 1
range.each_with_index do |letter, index|
print letter + " "
if index == length
puts "You are at last item"
end
end
This will print:
a b c d e f g h i j k l m n o p q r s t u v w x y z You are at last item
The enumerating enumerable series is pretty nice.
If blahs is a class that mixes in Enumerable, you should be able to do this:
blahs.each_with_index do |blah, i|
puts("#{i} #{blah}")
end

Resources