I'm trying to create an array of arrays to be used in a JavaScript function.
Here is the format of the array that I'm trying to create:
[[1,1],[2,3],[3,6],[4,10],[5,15],[6,21]]
Here is the ruby code to create the array:
total=0
foo=[]
(1..6).each do |number|
foo.push [number, total+=number]
end
puts foo
Here is the output of puts foo:
1
1
2
3
3
6
4
10
5
15
6
21
Any ideas how to output the correctly formatted array?
If I understand that correctly, you want to output the array somewhere in a document to be interpreted as JavaScript by the browser.
When it comes to using Ruby objects in JavaScript, you can use the JSON gem.
require 'json'
#create the array
foo.to_json
should do the trick.
This also works for hashes and some other object types.
Change puts foo to foo.inspect
total=0
foo=[]
(1..6).each do |number|
foo.push [number, total+=number]
end
foo.inspect
You can use p foo to print out the array:
total=0
foo=[]
(1..6).each do |number|
foo.push [number, total+=number]
end
p foo
This prints out: [[1, 1], [2, 3], [3, 6], [4, 10], [5, 15], [6, 21]]
Related
I've searched extensively but sadly couldn't find a solution to this surely often-asked question.
In Perl I can reassign an entire array within a function and have my changes reflected outside the function:
#!/usr/bin/perl -w
use v5.20;
use Data::Dumper;
sub foo {
my ($ref) = #_;
#$ref = (3, 4, 5);
}
my $ref = [1, 2];
foo($ref);
say Dumper $ref; # prints [3, 4, 5]
Now I'm trying to learn Ruby and have written a function where I'd like to change an array items in-place by filtering out elements matching a condition and returning the removed items:
def filterItems(items)
removed, items = items.partition { ... }
After running the function, items returns to its state before calling the function. How should I approach this please?
I'd like to change an array items in-place by filtering out elements matching a condition and returning the removed items [...] How should I approach this please?
You could replace the array content within your method:
def filter_items(items)
removed, kept = items.partition { |i| i.odd? }
items.replace(kept)
removed
end
ary = [1, 2, 3, 4, 5]
filter_items(ary)
#=> [1, 3, 5]
ary
#=> [2, 4]
I would search for pass by value/reference in ruby. Here is one I found first https://mixandgo.com/learn/is-ruby-pass-by-reference-or-pass-by-value.
You pass reference value of items to the function, not the reference to items. Variable items is defined out of method scope and always refers to same value, unless you reassign it in the variable scope.
Also filterItems is not ruby style, see https://rubystyle.guide/
TL;DR
To access or modify an outer variable within a block, declare the variable outside the block. To access a variable outside of a method, store it in an instance or class variable. There's a lot more to it than that, but this covers the use case in your original post.
Explanation and Examples
In Ruby, you have scope gates and closures. In particular, methods and blocks represent scope gates, but there are certainly ways (both routine and meta) for accessing variables outside of your local scope.
In a class, this is usually handled by instance variables. So, as a simple example of String#parition (because it's easier to explain than Enumerable#partition on an Array):
def filter items, separator
head, sep, tail = items.partition separator
#items = tail
end
filter "foobarbaz", "bar"
#=> "baz"
#items
#=> "baz"
Inside a class or within irb, this will modify whatever's passed and then assign it to the instance variable outside the method.
Partitioning Arrays Instead of Strings
If you really don't want to pass things as arguments, or if #items should be an Array, then you can certainly do that too. However, Arrays behave differently, so I'm not sure what you really expect Array#partition (which is inherited from Enumerable) to yield. This works, using Enumerable#slice_after:
class Filter
def initialize
#items = []
end
def filter_array items, separator
#items = [3,4,5].slice_after { |i| i == separator }.to_a.pop
end
end
f = Filter.new
f.filter_array [3, 4, 5], 4
#=> [5]
Look into the Array class for any method which mutates the object, for example all the method with a bang or methods that insert elements.
Here is an Array#push:
ary = [1,2,3,4,5]
def foo(ary)
ary.push *[6, 7]
end
foo(ary)
ary
#=> [1, 2, 3, 4, 5, 6, 7]
Here is an Array#insert:
ary = [1,2,3,4,5]
def baz(ary)
ary.insert(2, 10, 20)
end
baz(ary)
ary
#=> [1, 2, 10, 20, 3, 4, 5]
Here is an example with a bang Array#reject!:
ary = [1,2,3,4,5]
def zoo(ary)
ary.reject!(&:even?)
end
zoo(ary)
ary
#=> [1, 3, 5]
Another with a bang Array#map!:
ary = [1,2,3,4,5]
def bar(ary)
ary.map! { |e| e**2 }
end
bar(ary)
ary
#=> [1, 4, 9, 16, 25]
I am trying to create a method for objects that I create. In this case it's an extension of the Array class. The method below, my_uniq, works. When I call puts [1, 1, 2, 6, 8, 8, 9].my_uniq.to_s it outputs to [1, 2, 6, 8].
In a similar manner, in median, I'm trying to get the reference of the object itself and then manipulate that data. So far I can only think of using the map function to assign a variable arr as an array to manipulate that data from.
Is there any method that you can call that gets the reference to what you're trying to manipulate? Example pseudo-code that I could replace arr = map {|n| n} with something like: arr = self.
class Array
def my_uniq
hash = {}
each do |num|
hash[num] = 0;
end
hash.keys
end
end
class Array
def median
arr = map {|n| n}
puts arr.to_s
end
end
Thanks in advance!
dup
class Array
def new_self
dup
end
def plus_one
arr = dup
arr.map! { |i| i + 1 }
end
def plus_one!
arr = self
arr.map! { |i| i + 1 }
end
end
array = [1, 3, 5]
array.new_self # => [1, 3, 5]
array.plus_one # => [2, 4, 6]
array # => [1, 3, 5]
array.plus_one! # => [2, 4, 6]
array # => [2, 4, 6]
dup makes a copy of the object, making it a safer choice if you need to manipulate data without mutating the original object. You could use self i.e. arr = self, but anything you do that changes arr will also change the value of self. It's a good idea to just use dup.
If you do want to manipulate and change the original object, then you can use self instead of dup, but you should make it a "bang" ! method. It is a convention in ruby to put a bang ! at the end of a method name if it mutates the receiving object. This is particularly important if other developers might use your code. Most Ruby developers would be very surprised if a non-bang method mutated the receiving object.
class Array
def median
arr = self
puts arr.to_s
end
end
[1,2,3].median # => [1,2,3]
This question already has answers here:
Why am I getting objects printed twice?
(4 answers)
Closed 6 years ago.
# Call the each method of each collection in turn.
# This is not a parallel iteration and does not require enumerators.
def sequence(*enumerables, &block)
enumerables.each do |enumerable|
enumerable.each(&block)
end
end
# Examples of how these iterator methods work
a,b,c = [1,2,3],4..6,'a'..'e'
print "#{sequence(a,b,c) {|x| print x}}\n"
why the results is:
123456abcde[[1, 2, 3], 4..6, "a".."e"]
anyone could tell me why [[1, 2, 3], 4..6, "a".."e"] is getting printed?
or tell me why the return value of the 'sequence' method is [[1, 2, 3], 4..6, "a".."e"]??
Many thanks
sequence(a,b,c) { |x| print x }
prints 123456abcde and
print "#{some_code}\n"
will print the return value of some_code. In your example the each loops returns [[1, 2, 3], 4..6, "a".."e"], because the return value if each is self (see: http://apidock.com/ruby/v1_9_3_392/Enumerator/each)
I am trying to pass an array to a ruby script from a command line and facing some issue.
Here is the problem:
require 'pp'
def foo(arr1, var, arr2, var2)
puts arr1.class
pp arr1
pp arr1[0]
puts arr2.class
pp arr2
pp arr2[0]
end
foo [1, 2], 3, [5, 6], 8
Here is the output:
Array
[1, 2]
1
Array
[5, 6]
5
All is fine so far. Now I change my script to accept argument from the command line:
require 'pp'
def foo(arr1,var)
puts arr1.class
pp arr1
pp arr1[0]
end
foo ARGV[0],3
Here is the output:
jruby test.rb [1, 2], 3, [5, 6], 8
String
"[1,"
91
String
"2],"
50
As you can see, the array gets passed as a string and arr[0] basically prints the ascii value.
So the question is how do I pass an array from the command line , hopefully in one line.
Also I believe this question is related to all shell invocations than just ruby ?
I am using bash shell.
Update:
Just updated the question to indicate that there can be multiple arrays at different positions
Here's a list of ways to accomplish this. Stay away from the eval-based solutions. My favorite (though I don't know ruby, but this is my favorite:
irb(main):001:0> s = "[5,3,46,6,5]"
=> "[5,3,46,6,5]"
irb(main):002:0> a = s.scan( /\d+/ )
=> ["5", "3", "46", "6", "5"]
irb(main):003:0> a.map!{ |s| s.to_i }
=> [5, 3, 46, 6, 5]
The arguments will always come in as string, you need to find a way to turn them into the format you want, in your example an array of values, followed by a single value. I suggest using trollop for this, to take the heavy lifting out of dealing with the arguments. It can accept multi-value arguments, e.g.
require 'trollop'
opts = Trollop.options do
opt :array, 'an array', type: :ints
opt :val, 'a value', type: :int
end
puts "array: #{opts[:array].inspect}"
puts "val: #{opts[:val].inspect}"
Then you can do:
$ ruby test.rb -a 1 2 -v 3
array: [1, 2]
val: 3
And extra nice:
$ ruby test.rb --help
Options:
--array, -a <i+>: an array
--val, -v <i>: a value
--help, -h: Show this message
You can use eval although you might open a security hole:
require 'pp'
def foo(arr1, var, arr2, var2)
puts arr1.class
pp arr1
pp arr1[0]
puts arr2.class
pp arr2
pp arr2[0]
end
eval("foo " + ARGV.join(" "))
Result
Array
[1, 2]
1
Array
[5, 6]
5
Hope it helps
I always use a counter to check for the first item (i==0) in a loop:
i = 0
my_array.each do |item|
if i==0
# do something with the first item
end
# common stuff
i += 1
end
Is there a more elegant way to do this (perhaps a method)?
You can do this:
my_array.each_with_index do |item, index|
if index == 0
# do something with the first item
end
# common stuff
end
Try it on ideone.
Using each_with_index, as others have described, would work fine, but for the sake of variety here is another approach.
If you want to do something specific for the first element only and something general for all elements including the first, you could do:
# do something with my_array[0] or my_array.first
my_array.each do |e|
# do the same general thing to all elements
end
But if you want to not do the general thing with the first element you could do:
# do something with my_array[0] or my_array.first
my_array.drop(1).each do |e|
# do the same general thing to all elements except the first
end
Arrays have an "each_with_index" method which is handy for this situation:
my_array.each_with_index do |item, i|
item.do_something if i==0
#common stuff
end
What fits best is depending on the situation.
Another option (if you know your array is not empty):
# treat the first element (my_array.first)
my_array.each do | item |
# do the common_stuff
end
each_with_index from Enumerable (Enumerable is already mixed in with Array, so you can call it on an array without any trouble):
irb(main):001:0> nums = (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
irb(main):003:0> nums.each_with_index do |num, idx|
irb(main):004:1* if idx == 0
irb(main):005:2> puts "At index #{idx}, the number is #{num}."
irb(main):006:2> end
irb(main):007:1> end
At index 0, the number is 1.
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
If you don't need the array afterwards:
ar = %w(reversed hello world)
puts ar.shift.upcase
ar.each{|item| puts item.reverse}
#=>REVERSED
#=>olleh
#=>dlrow
Ruby's Enumerable#inject provides an argument that can be used for doing something differently on the first iteration of a loop:
> l=[1,2,3,4]
=> [1, 2, 3, 4]
> l.inject(0) {|sum, elem| sum+elem}
=> 10
The argument is not strictly necessary for common things like sums and products:
> l.inject {|sum, elem| sum+elem}
=> 10
But when you want to do something different on the first iteration, that argument might be useful to you:
> puts fruits.inject("I like to eat: ") {|acc, elem| acc << elem << " "}
I like to eat: apples pears peaches plums oranges
=> nil
Here's a solution that doesn't need to be in an immediately enclosing loop and avoids the redundancy of specifying a status placeholder more than once unless you really need to.
do_this if ($first_time_only ||= [true]).shift
Its scope matches the holder: $first_time_only will be globally once; #first_time_only will be once for the instance, and first_time_only will be once for the current scope.
If you want the first several times, etc, you can easily put [1,2,3] if you need to distinguish which of the first iterations you're in, or even something fancy [1, false, 3, 4] if you need something weird.