I'm not a programmer but find myself writing some simple Ruby. I need to populate an array with a list of IP addresses, 10.13.203.3, 10.13.204.3, etc.
I know that I can expand a range into an array like this, but how could I turn that into my IP address pattern?
a =* (3..10)
#=> [3, 4, 5, 6, 7, 8, 9, 10]
I was thinking I would need to do string interpolation and somehow feed it back into a different array. But I'm really not sure and mustn't be Googling correctly because this feels like a common thing that would be done.
You can use the IPAddr class, specifically the method IPAddr::new.
I have written the method to take three arguments, the first IP, the next IP and the total number of IPs to generate while maintaining the difference between the first and second IPs.
require 'ipaddr'
def gen_ips(ip_start, ip_next, number)
ips, ipn = [ip_start, ip_next].map { |ip| IPAddr.new(ip) }
(ips..IPAddr.new("255.255.255.255")).
step(ipn.to_i-ips.to_i).
lazy.
map { |ip| ip.to_s }.first(number)
end
gen_ips("10.13.203.3", "10.13.204.3", 6)
# => ["10.13.203.3", "10.13.204.3", "10.13.205.3", "10.13.206.3",
# "10.13.207.3", "10.13.208.3"]
gen_ips("10.13.254.250", "10.13.254.252", 6)
#=> ["10.13.254.250", "10.13.254.252", "10.13.254.254", "10.13.255.0",
# "10.13.255.2", "10.13.255.4"]
The second example shows what happens when the next IP rolls a digit in a preceding group.
I used Enumerable#lazy to convert the enumerator to a lazy one, so first(number) would be invoked as soon as number of elements of the mapping had been computed (rather than waiting until the enumerator had generated the last one in the range, IPAddr('255.255.255.255')).
You're looking for map
Ranges are enumerables so you can call map on them. And it's also simpler and easier to understand:
(203..210).map { |i| "10.13.#{i}.3" }
Would give you:
#=> ["10.13.203.3", "10.13.204.3", "10.13.205.3", "10.13.206.3", "10.13.207.3", "10.13.208.3", "10.13.209.3", "10.13.210.3"]
(203..210).inject([]) { |ar, i| ar << "10.13.#{i}.3" }
# [
# "10.13.203.3",
# "10.13.204.3",
# "10.13.205.3",
# "10.13.206.3",
# "10.13.207.3",
# "10.13.208.3",
# "10.13.209.3"
# "10.13.210.3"
# ]
References:
Enumerable#inject
Related
So I'm given a sorted array containing n >= 2 number of integers. These integers are used to represent wireless sensors and each has a broadcast radius of 2, meaning that if I had a number "4" it can reach at most "2" or "6". So I need to design an algorithm that returns an array containing all pairs of sensors (as subarrays) that can communicate with each other, possibly having their message forwarded by some intermediate sensor, eg. "8" is able to communicate with "12" given "10" exists in the array. The algorithm also needs to run in O(n^2) time.
So at first it was pretty simple, I would just get the length of the array, n, and iterate through it using a while loop (i < n) and if the current element + 2 was greater or equal to the following element, add its index and the following element's index to a subarray and add it to an empty array. But I was having problems with the intermediate sensor part. How would I find the intermediate sensor connections though?
Sort the list (takes O(NlogN) time)
Start traversing the array
See if the current element can communicate with our current set. If yes, then add it to the set and continue. Else, store the old set, create a new one and add current element to it.
For each set, generate all pairs of sensors that can communicate.
Something like:
def generate_pairs(array):
pairs = []
array_length = len(array)
for i in range(0, array_length):
for j in range(i+1, array_length):
pairs.append([array[i],array[j]])
return pairs
main_list = [1,2,4,7,9,10,13]
main_list.sort()
curr_set = [main_list[0]]
all_sets = []
for i in range (1,len(main_list)):
if main_list[i]-main_list[i-1] <=2:
curr_set.append(main_list[i])
else:
all_sets.append(curr_set)
curr_set = [main_list[i]]
all_pairs = []
for i in all_sets:
all_pairs += generate_pairs(i)
print(all_pairs)
# prints [[1, 2], [1, 4], [2, 4], [7, 9], [7, 10], [9, 10]]
I am writing code in Ruby.
Say I have an array like this:
myarray = [1,2,3,4,5]
I want to change the code of the Array class so that myarray[7] would return "out of bounds" instead of nil.
I don't want to make so that I check if something is out of bounds and then return "out of bounds", I want to implement this in Array directly.
Is this possible? Do I have to extend the Array class?
I'm Not sure how to start, very new to ruby. My initial thoughts were overriding a method in the Array class, but I'm not sure how to do that when I don't know what method is being used in myarray[i].
Suppose
arr = [1,2,3,4,5]
Let's start by examining the doc Array#[]. As seen, that method can have a single integer argument:
arr[2] #=> 3
arr[-2] #=> 4
arr[5] #=> nil
arr[-7] #=> nil
arr['x'] #=> TypeError (no implicit conversion of String into Integer)
or it may have two integer arguments:
arr[1,3] #=> [2, 3, 4]
arr[-3,2] #=> [3, 4]
arr[3,5] #=> [4, 5]
arr[7,4] #=> nil
arr[2,'x'] #=> TypeError (no implicit conversion of String into Integer)
or it may have a range of integers as an argument:
arr[1..3] #=> [2, 3, 4]
arr[1...3] #=> [2, 3]
arr[-5..-2] #=> [1, 2, 3, 4]
arr[3..9] #=> [4, 5]
arr[7..10] #=> nil
arr[1..'x'] #=> ArgumentError (bad value for range)
As I understand, you wish to alter Array#[] in such way that its behavior is unchanged except for the case when its argument is a single integer representing an offset into the array that is out-of-bounds.1. That could be done by writing the method in a module and then prepend that module to the class Array with the method Module#prepend.
module NewSlice
def [](*args)
arg1, arg2 = args
if arg2.nil? && arg1.is_a?(Integer) &&
(arg1 > self.size-1 || arg1 < -self.size)
"out of range"
else
super
end
end
end
Array.prepend(NewSlice)
arr[2] #=> 3
arr[-2] #=> 4
arr[5] #=> "out of range"
arr[-7] #=> "out of range"
arr['x'] #=> TypeError (no implicit conversion of String into Integer)
arr[1,3] #=> [2, 3, 4]
arr[-3,2] #=> [3, 4]
arr[3,5] #=> [4, 5]
arr[7,4] #=> nil
arr[2,'x'] #=> TypeError (no implicit conversion of String into Integer)
arr[1..3] #=> [2, 3, 4]
arr[1...3] #=> [2, 3]
arr[-5..-2] #=> [1, 2, 3, 4]
arr[3..9] #=> [4, 5]
arr[7..10] #=> nil
arr[1..'x'] #=> ArgumentError (bad value for range)
We see that
Array.ancestors
#=> [NewSlice, Array, Enumerable, Object, Kernel, BasicObject]
showing that super in NewSlice#[] calls the original method Array#[] after NewSlice has been prepended to Array. Since super has no arguments all the arguments that were passed to the new Array#[] method ( defined in NewSlice) are passed to the original Array#[].
Aliases were commonly used in Ruby prior to the introduction of Module#prepend in Ruby v2.0. They are still used but their importance has diminished greatly since prepend has become available.
If nil is to be replaced by "out of bounds" in all cases where Array#[] returns nil, write
module NewSlice
def [](*args)
super || "out of bounds"
end
end
Array.prepend(NewSlice)
arr[5] #=> "out of range"
arr[-7] #=> "out of range"
arr[7,4] #=> "out of range"
arr[7..10] #=> "out of range"
1. Whether it is advisable to modify core methods such as Array#[] is a separate question, but it can result in pain and suffering.
TL;DR
This is an interesting question about how to monkeypatch core Ruby classes like Array. However, I'd be remiss if I didn't point out that it involves some hijinks that seem unnecessary, since you could get the same behavior with a simple logical OR operator like:
[1, 2, 3][5] || 'out of bounds'
#=> "out of bounds"
Still, if you want to change the behavior of a core class then it can certainly be done.
Re-Open the Core Class
In Ruby, almost everything that isn't a keyword is a method. Pragmatically, Array::[] is really just a method for indexing into an array object, with a little syntactic sugar from the interpreter to allow its arguments to be placed inside the brackets. Because it's just an instance method defined by the Array class, it can be modified in various ways such as re-opening the core class to modify the method, or by creating a singleton method on the instance. The first is conceptually simpler, but singleton methods are probably the safest solution for real-world programming.
You can re-open the Array class and redefine Array::[] as follows:
class Array
# save off a copy of the existing method; we still need it
alias_method :'old_[]', :'[]' unless defined? Array::old_[]
# pass all arguments to the old method, but return a string
# when the result is falsey
def [] *args
send("old_[]", *args) || 'out of bounds'
end
end
You can then demonstrate that it works like a regular Array, but with your expected behavior:
a = [10, 20, 30]
a[0] #=> 10
a[0,2] #=> [10, 20]
a[100] #=> "out of bounds"
Add a Singleton Method
While the code above works, it's just generally a bad idea to monkeypatch a core class like Array. If you don't want to encapsulate this behavior in a subclass (e.g. class MyArray < Array), then you should use refinements (using Module#refine) or singleton methods like the following to reduce the scope of your changes. For example:
a = [10, 20, 30]
class << a
alias_method :'old_[]', :'[]' unless self.respond_to? 'old_[]'
def [] *args
send("old_[]", *args) || 'out of bounds'
end
end
By limiting the scope of our change to a single instance, we're much less likely to cause serious or unrecoverable problems with core classes. A lot of things can go wrong in a Ruby program if a core class like Array starts returning truthy values (e.g. a String value such as out of bounds) rather than a falsey value like nil, so caveat emptor!
If you really want to break existing code (standard classes and ruin even methods of the current Array class itself, which rely on the current behaviour), you can of course monkeypatch it - open it and redefine the method in any way you like, as has been outlined in various answers to this question.
A more sane approach would be to subclass Array, i.e.
class BoundCheckingArray < Array
# redefined the methods according to your taste.
end
Of course this would violate the Liskov Substitution Principle.
Another approach will be to define a complete separate class and use Delegator to avoid rewriting everything from scratch, by delegating methods you did not rewrite explicitly, to the underlying array.
In both cases you need to be aware, that those methods in your BoundCheckingArray, which you did not explicitly rewrite and hence are taken from BoundCheckingArray, will stop working, if they assume that they can safely access the array outside of the bounds.
Another possibility would be to not modify existing Array methods, but simply add bound checking setters and getters, i.e. with monkeypatching:
class Array
def at_checked(i)
fail "out_of_bounds" if i >= size || i < -size
at(i)
end
def set_checked(i, new_value)
# analoguous
end
end
Of course this approach would also work with subclassing (now adhering to Liskov's principle, because you just added methods) and delegating. Note that I coped explicitly with negative index values, assuming that you would like to use this feature in your bound checking array too.
You may know classes in Ruby are defined like:
class Foo
def foo
'foo'
end
end
Foo.new.foo # calls instance method `foo` on the instance of `Foo`
# => 'foo'
Classes and modules in Ruby can be "reopened" for re-definition (although it's a bit frowned upon -- makes it difficult to track code b/c code can be in either/any place):
class Foo
def bar
'bar'
end
def foo
'overwrite foo'
end
end
f = Foo.new
f.bar
# => 'bar'
f.foo
# => 'overwrite foo'
This means you can also do:
class Array
# re-define anything you want
end
# alternatively:
Array.class_eval do
# the same as the above, in most ways
end
Even though it's even less recommended to modify existing methods of core Ruby classes. Not only does it break assumptions other Ruby developers may have of the code (i.e. misleading code), its global effect will likely break behaviors in other libraries, etc.
Is it possible to save and access array or list containing elements with different length? For instance, I want to save data=[s,r,a,se] r,a are scalar but s and se are an arrays with 4 elements.(in python language)
For instance in one time:(s,r,a,se) are different in different times
s=[1,3,4,6] r=5 a=7 se=[11,12,13,14]
data=[s,r,a,se]=[[1,3,4,6],5,7,[11,12,13,14]]
How I can define the array containing them to be able to call them similar to the following code:
s=[data[0] for data in minibatch]
r=[data[1] for data in minibatch]
a=[data[2] for data in minibatch]
se=[data[3] for data in minibatch]
Also, how I can extract (Find) that is there a special[stest,rtest,atest,setest] in data (stest,setest are with 4 elements)
For instance: I want to see can I find [[1,2,3,4],5,6,[7,8,9,10]] in data which is something similar to: [ [[1,2,3,4],5,6,[7,8,9,10]] ,[[...,...,...,...],...,..., [...,...,...,...]], [[18,20,31,42],53,666,[27,48,91,120]]]
If I did not find I append to it otherwise nothing is happened!
You can add them in a new list:
new_list = [s, r, a, se]
But you'll have to be careful managing this list
# This is a great opportunity to explore dictionaries
# lets take the examples you have given in variales
s=[1,3,4,6]
r=5
a=7
se=[11,12,13,14]
# make a dictionary out of them, with keys which are
# the same as the variable name
my_dict = {'s':s,
'r':r,
'a':a,
'se':se}
# lets see what that looks like
print(my_dict)
print()
# to retrieve 2nd (=ix=1) element of s
# the format to do this is simple
# ditionary_variable_name['the string which is the key'][index_of_the_list]
s2 = my_dict['s'][1]
print(s2)
print()
# to retrieve all of se
se_retrieved = my_dict['se']
print(se_retrieved)
# you can further experiment with this
output of sample:
{'s': [1, 3, 4, 6], 'r': 5, 'a': 7, 'se': [11, 12, 13, 14]}
3
[11, 12, 13, 14]
In order to write to this, you need to do something like this:
my_dict['se'] = [15, 16, 17, 18]
or
my_dict['se'][2] = 19
I am still learning Perl 6. Please pardon my ignorance. I am reading the Operators page and I found some unfamiliar constructs at the start of a table:
A Level Examples
N Terms 42 3.14 "eek" qq["foo"] $x :!verbose #$array
I re-read class Array and class Scalar but I am unable to find #$xyz construct in those sections. What do :! and #$ mean? Is there a convenient place that gathers and explains all these symbolic constructs?
Thank you very much !!
#$foo is short for #($foo), where $foo is an item variable and the #(...) syntax simply calls the .list method on its argument. Both the method and the syntactic form are sometimes called the "list/array contextualizer".
One use for it, is when you want to iterate over an Array stored in an item container. An item container is considered a single item by built-ins such as for loops, whereas calling .list on it returns the plain Array without the surrounding item container (i.e. "forces the value to be interpreted in list context"):
my $foo = [1, 2, 3];
say $foo.perl; # $[1, 2, 3]
say $foo.list.perl; # [1, 2, 3]
say #$foo.perl; # [1, 2, 3]
for $foo { ... } # One iteration
for $foo.list { ... } # Three iterations
for #$foo { ... } # Three iterations (identical to the previous line)
:!foo is short for :foo(False), i.e. a named argument that has the value False:
sub do-something (:$verbose = True) { say $verbose; }
do-something; # True
do-something :verbose; # True
do-something :!verbose; # False
When written in term position but not as an argument of an argument list, it constructs a Pair object:
say (:!verbose); # verbose => False
Using a :verbose parameter would be a good way to set a Bool argument to True with a colon pair. It is equivalent to :verbose(True). :!verbose is just the negation of that, setting it to False, equivalent to :verbose(False).
#$ is a way of using the # prefix to remove the container from a scalar variable with sigil $.
Consider:
my $x = (1, 2, 3);
.say for $x;
Output:
(1 2 3)
vs.
my $x = (1, 2, 3);
.say for #$x;
Output:
1
2
3
Most operators can be searched for directly. These two cases in particular are not individual operators, but cases of using symbols in combination. Those are a little more difficult gather conveniently, but the docs are improving every day.
When I started writing Ruby many years ago, it took me a while to understand the difference between each and map. It only got worse when I discovered all the other Enumerable and Array methods.
With the help of the official documentation and many StackOverflow questions, I slowly began to understand what those methods did.
Here is what took me even longer to understand though :
Why should I use one method or another?
Are there any guidelines?
I hope this question isn't a duplicate : I'm more interested in the "Why?" than the "What?" or "How?", and I think it could help Ruby newcomers.
A more tl;dr answer:
How to choose between each, map, inject, each_with_index and each_with_object?
Use #each when you want "generic" iteration and don't care about the result. Example - you have numbers, you want to print the absolute value of each individual number:
numbers.each { |number| puts number.abs }
Use #map when you want a new list, where each element is somehow formed by transforming the original elements. Example - you have numbers, you want to get their squares:
numbers.map { |number| number ** 2 }
Use #inject when you want to somehow reduce the entire list to one single value. Example - you have numbers, you want to get their sum:
numbers.inject(&:+)
Use #each_with_index in the same situation as #each, except you also want the index with each element:
numbers.each_with_index { |number, index| puts "Number #{number} is on #{index} position" }
Uses for #each_with_object are more limited. The most common case is if you need something similar to #inject, but want a new collection (as opposed to singular value), which is not a direct mapping of the original. Example - number histogram (frequencies):
numbers.each_with_object({}) { |number, histogram| histogram[number] = histogram[number].to_i.next }
Which object can I use?
First, the object you're working with should be an Array, a Hash, a Set, a Range or any other object that respond to each. If it doesn't, it might be converted to something that will. You cannot call each directly on a String for example, because you need to specify if you'd like to iterate over each byte, character or line.
"Hello World".respond_to?(:each)
#=> false
"Hello World".each_char.respond_to?(:each)
#=> true
I want to calculate something with each element, just like with a for loop in C or Java.
If you want to iterate over each element, do something with it and not modify the original object, you can use each. Please keep reading though, in order to know if you really should.
array = [1,2,3]
#NOTE: i is a bound variable, it could be replaced by anything else (x, n, element). It's a good idea to use a descriptive name if you can
array.each do |i|
puts "La"*i
end
#=> La
# LaLa
# LaLaLa
It is the most generic iteration method, and you could write any of the other mentioned methods with it. We will actually, for pedagogical purposes only. If you spot a similar pattern in your code, you could probably replace it with the corresponding method.
It is basically never wrong to use each, it is almost never the best choice though. It is verbose and not Ruby-ish.
Note that each returns the original object, but this is rarely (never?) used. The logic happens inside the block, and should not modify the original object.
The only time I use each is:
when no other method would do. The more I learn about Ruby, the less often it happens.
when I write a script for someone who doesn't know Ruby, has some programming experience (e.g. C, Fortran, VBA) and would like to understand my code.
I want to get an Array out of my String/Hash/Set/File/Range/ActiveRecord::Relation
Just call object.to_a.
(1..10).to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
"Hello world".each_char.to_a
#=> ["H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
{:a => 1, :b => 2}.to_a
#=> [[:a, 1], [:b, 2]]
Movie.all.to_a #NOTE: Probably very inefficient. Try to keep an ActiveRecord::Relation as Relation for as long as possible.
#=> [Citizen Kane, Trois couleurs: Rouge, The Grapes of Wrath, ....
Some methods described below (e.g. compact, uniq) are only defined for Arrays.
I want to get a modified Array based on the original object.
If you want to get an Array based on the original object, you can use map. The returned object will have the same size as the original one.
array = [1,2,3]
new_array = array.map do |i|
i**2
end
new_array
#=> [1, 4, 9]
#NOTE: map is often used in conjunction with other methods. Here is the corresponding one-liner, without creating a new variable :
array.map{|i| i**2}
#=> [1, 4, 9]
# EACH-equivalent (For pedagogical purposes only):
new_array = []
array.each do |i|
new_array << i**2
end
new_array
#=> [1, 4, 9]
The returned Array will not replace the original object.
This method is very widely used. It should be the first one you learn after each.
collect is a synonym of map. Make sure to use only one of both in your projects.
I want to get a modified Hash based on the original Hash.
If your original object is a Hash, map will return an Array anyway. If you want a Hash back :
hash = {a: 1, b: 2}
hash.map{|key, value| [key, value*2]}.to_h
#=> {:a=>2, :b=>4}
# EACH-equivalent
hash = {a: 1, b: 2}
new_hash = {}
hash.each do |key,value|
new_hash[key]=value*2
end
new_hash
#=> {:a=>2, :b=>4}
I want to filter some elements.
I want to remove nil elements
You can call compact. It will return a new Array without the nil elements.
array = [1,2,nil,4,5]
#NOTE: array.map{|i| i*2} Would raise a NoMethodError
array.compact
# => [1, 2, 4, 5]
# EACH-equivalent
new_array = []
array.each do |integer_or_nil|
new_array << integer_or_nil unless integer_or_nil.nil?
end
new_array
I want to write some logic to determine if an element should be kept in the new Array
You can use select or reject.
integers = (1..10)
integers.select{|i| i.even?}
# => [2, 4, 6, 8, 10]
integers.reject{|i| i.odd?}
# => [2, 4, 6, 8, 10]
# EACH-equivalent
new_array = []
integers.each do |i|
new_array << i if i.even?
end
new_array
I want to remove duplicate elements from your Array
You can use uniq :
letters = %w(a b a b c)
letters.uniq
#=> ["a", "b", "c"]
# EACH-equivalent
uniq_letters = []
letters.each do |letter|
uniq_letters << letter unless uniq_letters.include?(letter)
end
uniq_letters
#TODO: Add find/detect/any?/all?/count
#TODO: Add group_by/sort/sort_by
I want to iterate over all the elements while counting from 0 to n-1
You can use each_with_index :
letters = %w(a b c)
letters.each_with_index do |letter, i|
puts "Letter ##{i} : #{letter}"
end
#=> Letter #0 : a
# Letter #1 : b
# Letter #2 : c
#NOTE: There's a nice Ruby syntax if you want to use each_with_index with a Hash
hash = {:a=>1, :b=>2}
hash.each_with_index{|(key,value),i| puts "#{i} : #{key}->#{value}"}
# => 0 : a->1
# 1 : b->2
# EACH-equivalent
i = 0
letters.each do |letter|
puts "Letter ##{i} : #{letter}"
i+=1
end
each_with_index returns the original object.
I want to iterate over all the elements while setting a variable during each iteration and using it in the next iteration.
You can use inject :
gauss = (1..100)
gauss.inject{|sum, i| sum+i}
#=> 5050
#NOTE: You can specify a starting value with gauss.inject(0){|sum, i| sum+i}
# EACH-equivalent
sum = 0
gauss.each do |i|
sum = sum + i
end
puts sum
It returns the variable as defined by the last iteration.
reduce is a synonym. As with map/collect, choose one keyword and keep it.
I want to iterate over all the elements while keeping a variable available to each iteration.
You can use each_with_object :
letter_ids = (1..26)
letter_ids.each_with_object({}){|i,alphabet| alphabet[("a".ord+i-1).chr]=i}
#=> {"a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5, "f"=>6, "g"=>7, "h"=>8, "i"=>9, "j"=>10, "k"=>11, "l"=>12, "m"=>13, "n"=>14, "o"=>15, "p"=>16, "q"=>17, "r"=>18, "s"=>19, "t"=>20, "u"=>21, "v"=>22, "w"=>23, "x"=>24, "y"=>25, "z"=>26}
# EACH-equivalent
alphabet = {}
letter_ids.each do |i|
letter = ("a".ord+i-1).chr
alphabet[letter]=i
end
alphabet
It returns the variable as modified by the last iteration. Note that the order of the two block variables is reversed compared to inject.
If your variable is a Hash, you should probably prefer this method to inject, because h["a"]=1 returns 1, and it would require one more line in your inject block to return a Hash.
I want something that hasn't been mentioned yet.
Then it's probably okay to use each ;)
Notes :
It's a work in progress, and I would gladly appreciate any feedback. If it's interesting enough and fit in one page, I might extract a flowchart out of it.