Ruby: Selecting a set of array indices whose elements pass a test - ruby

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.

Related

How to remove duplicate pair values from given array in Ruby?

I want to remove a pair of 'duplicates' from an array of strings, where each element has the form R1,R2, with varying numbers. In my case, a duplicate would be R2,R1 because it has the same elements of R1,R2 but inverted.
Given:
a = ['R1,R2', 'R3,R4', 'R2,R1', 'R5,R6']
The resulting array should be like so:
a = ['R1,R2', 'R3,R4', 'R5,R6']
How could I remove the duplicates so I would have the following?
A solution with Set
require 'set'
a.uniq { |item| Set.new(item.split(",")) } # => ["R1,R2", "R3,R4", "R5,R6"]
Here is a working example :
array = ['R1,R2', 'R3,R4', 'R2,R1', 'R5,R6']
array.uniq { |a| a.split(',').sort }
try this,
def unique(array)
pure = Array.new
for i in array
flag = false
for j in pure
flag = true if (j.split(",").sort == i.split(",").sort)
end
pure << i unless flag
end
return pure
end
reference: https://www.rosettacode.org/wiki/Remove_duplicate_elements#Ruby
If the elements of your array are "pairs", they should maybe be actual pairs and not strings, like this:
pairs = [['R1', 'R2'], ['R3', 'R4'], ['R2', 'R1'], ['R5', 'R6']]
And, in fact, since order doesn't seem to matter, it looks like they really should be sets:
require 'set'
sets = [Set['R1', 'R2'], Set['R3', 'R4'], Set['R2', 'R1'], Set['R5', 'R6']]
If that is the case, then Array#uniq will simply work as expected:
sets.uniq
#=> [#<Set: {"R1", "R2"}>, #<Set: {"R3", "R4"}>, #<Set: {"R5", "R6"}>]
So, the best way would be to change the code that produces this value to return an array of two-element sets.
If that is not possible, then you should transform the value at your system boundary when it enters the system, something like this:
sets = a.map {|el| el.split(',') }.map(&Set.method(:new))

Is there a better way?: iterating over an array in ruby

I'm working on a mini project for a summer class. I'd like some feedback on the code I have written, especially part 3.
Here's the question:
Create an array called numbers containing the integers 1 - 10 and assign it to a variable.
Create an empty array called even_numbers.
Create a method that iterates over the array. Place all even numbers in the array even_numbers.
Print the array even_numbers.
Here's my code, so far:
numbers = [1,2,3,4,5,6,7,8,9,10]
print numbers[3]
even_numbers.empty?
def even_numbers
numbers.sort!
end
Rather than doing explicit iteration, the best way is likely Array#select thus:
even_numbers = numbers.select { |n| n.even? }
which will run the block given on each element in the array numbers and produce an array containing all elements for which the block returned true.
or an alternative solution following the convention of your problem:
def get_even_numbers(array)
even_num = []
array.each do |n|
even_num << n if n.even?
end
even_num
end
and of course going for the select method is always preferred.

Ruby array subtraction?

Either I don't understand what happens when you subtract an array from an array, or something is wrong here.
What I have is a list of usernames (strings) in an array:
users.count - users.uniq.count # => 9
users - users.uniq # => []
I'm not sure how this is possible.
I'm essentially trying to find a list of the duplicates. I realize there are other ways to go about this, just trying to understand Array operations better.
Here is the workaround code I used to get the same:
users.inject(Hash.new(0)) {|h,i| h[i] += 1; h}.select{|k,v| v > 1}
You could use
dups = users.select{|e| users.count(e) > 1 }.uniq
Or, to find only a single duplicate element:
firstDup = users.detect {|e| users.count(e) > 1 }
About the array subtraction, this may clarify:
a = [1, 1, 1, 1, 1]
a - [1] # => []
Array subraction removes all occurences, not just one.
The behavior of Array#- is quite correct. It
Returns a new array that is a copy of the original array, removing any
items that also appear in other_ary.
The user list (with duplicates) without all the users is empty.
Coming from "Ruby: How to find and return a duplicate value in array?", the following seems to be good at finding duplicates in an Array:
users.detect {|e| users.rindex(e) != users.index(e) }

Index a ruby array to omit an element or range of elements?

I have a ruby array of, say, 10 elements, and I'd like to return all but the 5th element.
a = *(1..10)
I'd like to be able to do something like
a[0..3 + 5..9]
Or even better something like (borrowing from the R syntax),
a[-4]
to do this, but that doesn't work. (Nor does anything more clever I've tried like getting an array of the element indices). What's the best way to do this in ruby?
You can use values_at: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-values_at
so you may use it as
a.values_at(0..3, 5..9)
No black magic required:
a[0..3] + a[5..9]
Look in the documentation under Array#delete_at
For example, myarray.delete_at(5) results in the array lacking what was element 5 (counting from 0, of course).
Example:
class Array
def without(n)
self.delete_at(n)
return self
end
end
arr = [1, 2, 3, 4]
p arr.without(1) #=> [1, 3, 4]
However, as a commenter points out, this alters the original array, which may not be what the O.P. wants! If that's an issue, write it like this:
class Array
def without(n)
arr2 = Array.new(self)
arr2.delete_at(n)
return arr2
end
end
That returns the desired array (an array lacking the nth element of the original) while leaving the original array untouched.

Delete one of many from Array

I have an Array that contains some elements multiple times. Now I want to create a new Array with one of those elements deleted.
Example:
a = [1,1,1,2]
delete_index = a.find_index(1)
result = a.clone
result.delete_at(delete_index)
# result is now [1,1,2]
This code looks really ugly for such an easy task. I had a look at the methods that Array provides, but couldn't find a better way of doing this.
a.delete_at(a.index(1) || a.length)
a.length handles the case where your element isn't found; because it's out of range, nothing will be deleted and your return value wil be nil.
If part of your question was to do this to a copy of the array, just call it on a clone:
a2 = a.clone ; a2.delete_at(...)
If you want to do this for each duplicated element, you can chain it to a block that selects the duplicated elements:
a.select { |e| array.count(e) > 1 }.each { |dup| a.delete_at a.index(dup) }
You could monkey patch Array:
class Array
def delete_first_occurrence(o)
delete_at(find_index(o) || length)
self
end
end
a = [1,1,1,2]
result = a.clone.delete_first_occurrence(1)
=> [1, 1, 2]
I can't quite tell, but it sounds like you're just trying to remove duplicates from the array. If that's the case, it's as easy as array.uniq, which will return a new array with all duplicates removed. If you'd like to modify the original array in place, you can use array.uniq! instead.
If that's not what you're trying to accomplish, please update your question with some example input and output of what you're trying to accomplish.

Resources