I have a multidimensional array like this:
main_array = [ [["a","b","c"],["d","e"]], [["e","f"],["g","h"]] ]
And I would like to check whether main_array contains other arrays.
I've thought that this will work main_array.include?(Array), but i was wrong.
To answer your question directly, I will use #grep method
main_array.grep(Array).empty?
This will ensure that, if your main_array contains at least one element as Array, if returns false.
main_array.grep(Array).size == main_array.size
This will tell you, if all elements are array or not.
You can use the Enumerable#all? if you want to check that the main array contains all arrays.
main_array.all? { |item| item.is_a?(Array) }
or Enumerable#any?
main_array.any? { |item| item.is_a?(Array) }
if you want to check if main_array contains any arrays.
You can use Enumerable#any?:
main_array.any?{|element| element.is_a? Array}
The code you tried (main_array.include?(Array) didn't work because it's checking if the array main_array includes the class Array, e.g. [Array].include?(Array) #=> true).
main_array != main_array.flatten
Related
I need a function to check if an array contains other arrays, or more generally if an array contains a certain class. My naive first approach is:
found=false
[1,"a",[],:asdf].each { |x| found=(x.is_a? Array) ? true : found }
puts found
Any way to optimize this?
In newer Rubies (2.5+) you don't need to pass a block to any?. That links goes to the latest docs, which has a similar example checking for integers.
Therefore, you can simply use:
[1, "a", [], :asdf].any?(Array)
# => true
[1, "a", :asdf].any?(Array)
# => false
That seems the simplest syntax and most sensible approach here if your Ruby version allows it :)
You can try #any?
For example:
[1,"a",[],:asdf].any? { |el| el.is_a? Array }
#=> true
Almost always when you find yourself using each, you are missing some higher-level abstraction.
In this case, that abstraction is the method Array#any?, which will return true if any element of the array satisfies the predicate:
[1, "a", [], :asdf].any?(Array)
this approach iterate over all elements even if you found an array.
in your test case it will iterate over :asdf,
and you don't have to check this.
I think you need to break from loop if you found the certain type(Array in our Example).
found = false
[1,"a",[],:asdf].each do |x|
if x.is_a? Array
found = true
break
end
end
puts found
Also you can use any instead of each
found = [1,"a",[],:asdf].any? { |x| x.is_a? Array }
puts found # true
I am adding to an array using:
server.bans << { :mask => "#{user}", :who => "#{server}", :when => Time.now.to_i }
What is the simplest method to reverse this command?
Should I be using .remove? If so what should I pass to it, the same as what I used in the <<?
You can use Array#pop to remove the last element of the array:
server.bans.pop
You can also use Array#delete_if, if you want to remove elements which meet certain criteria:
server.bans.delete_if{ |u| u[:mask] == "#{user}" }
You could get the object_id of each element in the Array to use as a future reference. While using pop will work, it is not available once another element of the Array is added.
To view object_id of elements. Possibly store these in it's own Array.
server.bans do |ban|
puts ban.object_id
end
Ruby array provide delete_if method to delete items from array conditions. You can use this method as
server.bans.delete_if{ |u| u[:mask] == user.to_s }
To get more details of delete_if http://ruby-doc.org/core-2.2.2/Array.html#method-i-delete_if
Further you can also user remove! method
Example:
my_array = ['2823BII','4A','76B','10J']
[using magical method delete_if_doesnt_contain()]
my_array.map! do |elements|
elements.delete_if_doesnt_contain('A')
end
I want that to set my_array = ['4A']
Even if I could iterate through an array and just return the index of the element that contains an 'A' I'd be happy. Thanks for any help!
Thanks for the answers below, but one more question.
other_array = ['4']
my_var = other_array.to_s
my_array.select!{|x| x.include?(my_var)}
This isn't working for me. What am I missing? Something happen when I converted the array to a string?
Very easy using #select :
my_array = ['2823BII','4A','76B','10J']
my_array.select { |str| str.include?('A') }
# => ["4A"]
Or if you want to modify the source array, do use the bang version of select :-
my_array.select! { |str| str.include?('A') }
Arup's answer is correct.
However, to answer your last question specifically, "iterate through an array and just return the index of the element that contains an 'A'", the "index" method returns the index for a matching element:
my_array.index {|x| x.include?('A') }
The grep method is a lot shorter
my_array = ['2823BII','4A','76B','10J']
my_array.grep /A/
I have to sort through a (rows)array of (row)arrays. The (row)arrays contain an arbitrary number of strings. If a (row)array contains only empty strings I want to remove it from the (rows)array.
I'm currently doing this:
rows.each do |row|
row.each_index do |i|
if row[i].length > 0
break
elsif i == row.count-1
rows.delete(row)
end
end
end
But is there a more elegant way to do it?
Slightly more concise:
rows.reject! { |row| row.all?(&:empty?) }
Modifying an array while you iterate though it is not a good idea - you may find your code skips certain elements or does weird stuff. I'd do
rows.reject! {|row| row.all? {|row_element| row_element.empty?}}
We reject a row if the block row_element.empty? evaluates to true for all elements in the row. It's well worth getting familiar with all of the methods in Enumerable, they're very handy for this sort of task.
when using rails:
! rows.any?(&:present?)
You can use compact.uniq or compact. If your arrays have nil values, compact will result in an empty array, so you can check for that like this:
row.compact.size == 0
if row contains empty strings "" you can check for it like this:
row.compact.uniq.first.blank? and row.size == 1
rows.select{|row| row.compact.count >0}
Here: rows.all?(&:blank?).
Ruby has a select method that takes an array and returns a subarray consisting of all the elements that pass the test given in a block:
myarray.select{|e| mytest(e)} #=> subarray of elements passing mytest
I am wondering whether there is a simple method to get not these elements, but their indices. I understand you could do this:
indices = []
myarray.each_with_index{|e,i| indices << i if mytest(e)}
But I'm looking for a one-liner. Does one exist? Please don't write an extension to the Array class, I know you can get a one-liner that way.
Another one-liner:
(0...myarray.length).select {|i| mytest(myarray[i])}
Cheers!
Here's a one-liner for you. It selects indexes of elements whose length is 3.
a = ['foo', 'bar', 't']
a.map.with_index{|el, i| i if el.length == 3}.compact # => [0, 1]
Or another one (suggested by #fl00r):
a.reduce([]){|ar,el| ar << a.index(el) if el.size == 3; ar}
Also,
myarray.select{|e| mytest(e)}.map!{|e| myarray.index(e)}
However, this won't work properly if you have any repeated elements.