Delete array element if index position is greater than a specific value - arrays

I am trying to delete elements from an array if its index is greater than a certain value. I am looking to do something like this:
a = ["a", "b", "c"]
b = a.delete_if {|x| x.index > 1 }
I took a look at drop, delete_if, etc. I tried completing this using each_with_index like this:
new_arr = []
a.each_with_index do |obj, index|
if index > 1
obj.delete
end
new_arry << obj
end
How can I delete an array element if it's array position is greater than a certain value?

Here are some other ways to return a sans elements at indices >= index, which is probably better expressed as "returning the first index elements". All below return ["a", "b"]).
a = ["a", "b", "c", "d", "e"]
index = 2
Non-destructive (i.e., a is not altered)
a[0,index]
index.times.map { |i| a[i] }
Destructive (a is modified or "mutated")
a.object_id #=> 70109376954280
a = a[0,index]
a.object_id #=> 70109377839640
a.object_id #=> 70109377699700
a.replace(a.first(index))
a.object_id #=> 70109377699700

You can use slice! and give it a range. It is a destructive method as indicated by the !, so it will mutate your array.
a = [1, 2, 3, 4]
a.slice!(2..-1)
a = [1, 2]

Array#first gives you the first n elements.
b = a.first(1)
# => ["a"]
If you want to do it in a destructive way, then this will do:
a.pop(a.length - 1)
a # => ["a"]

You can append with_index:
a = ["a", "b", "c"]
a.delete_if.with_index { |x, i| i > 1 }
a #=> ["a", "b"]
Another example:
a = ("a".."z").to_a
a.delete_if.with_index { |x, i| i.odd? }
#=> ["a", "c", "e", "g", "i", "k", "m", "o", "q", "s", "u", "w", "y"]

Going by your question, "How can I delete an array element if it's array position is greater than a certain value?".
I assume what you want is that the final array you have should contain only elements before the specified index.
You can just do this:
your_array.select { |element| your_array.index(element) < max_index }
E.g
figures = [1,2,3,4,5,6]
figures.select{ |fig| figures.index(fig) < 3 }
# => [1, 2, 3]

Related

Output is given in 2 lines after concatenation of elements with odd and even indexes in a given string

I wrote a function which takes all elements with odd indexes and concatenates them with all elements with even indexes in a given string n times:
def encrypt(text,n)
while n > 0
n -= 1
str_array = text.split("")
even_values = str_array.select.with_index { |_, i| i.even? }
odd_values = str_array.select.with_index { |_, i| i.odd? }
text = (odd_values+even_values).join
end
puts text
end
puts 'Type your message to encrypt:'
text = gets
puts 'Type number of times to run encryption:'
n = gets.to_i
encrypt(text,n)
The issue is that in case the input text has odd number of elements the function will return a text in 2 lines. At the same time if number of elements of input text is even the output is a 1 line text which is what I want.
Console output with 10 elements in input text:
Type your message to encrypt:
abcdefghij
Type number of times to run encryption:
1
bdfhjacegi
Console output with 11 elements in input text:
Type your message to encrypt:
abcdefghijk
Type number of times to run encryption:
1
bdfhj
acegik
For n = 1
def doit(str)
enum = [false, true].cycle
str.each_char.partition { enum.next }.map(&:join).join
end
doit "abcdefghij"
#=> "bdfhjacegi"
doit "abcdefghijk"
#=> "bdfhjacegik"
For n > 1
n.times.reduce(str) { |s,_| doit(s) }
For example:
4.times.reduce(str) { |s,_| doit(s) }
#=>"ejdichbgafk"
See Enumerable#reduce (a.k.a. inject)
Now consider the calculations performed by doit.
First consider the enumerator enum, created with the method Array#cycle:
enum = [false, true].cycle
#=> #<Enumerator: [false, true]:cycle>
We can use the method Enumerator#next to see what values this enumerator enum will generate:
enum.next
#=> false
enum.next
#=> true
enum.next
#=> false
... ad infinitum
Now let's reset the enumerator using Enumerator#rewind:
enum.rewind
#<Enumerator: [false, true]:cycle>
Suppose
str = "abcdefghijk"
Then
e = str.each_char
#=> #<Enumerator: "abcdefghijk":each_char>
We can convert this enumerator to an array to see what elements it will generate.
e.to_a
#=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"]
Continuing,
a = e.partition { enum.next }
#=> [["b", "d", "f", "h", "j"], ["a", "c", "e", "g", "i", "k"]]
b = a.map(&:join)
#=> ["bdfhj", "acegik"]
b.join
#=> "bdfhjacegik"
Note a.map(&:join) is shorthand for a.map { |arr| arr.join }.
See String#each_char, Enumerable#partition and Array#join.

How do I split an array into smaller arrays bsaed on a condition?

Ruby 2.4. I have an array of strings
2.4.0 :007 > arr = ["a", "b", "g", "e", "f", "i"]
=> ["a", "b", "g", "e", "f", "h", "i"]
How do I split my array into smaller arrays based on a condition? I have a function -- "contains_vowel," which returns true if a string contains "a", "e", "i", "o", or "u". How would I take an array of strings and split it into smaller arrays, using a divider function of "contains_vowel"? That is, for the above, the resulting array of smaller arrays would be
[["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
If an element of the larger array satisfies the condition, it would become an array of one element.
arr = ["a", "b", "g", "e", "f", "i"]
r = /[aeiou]/
arr.slice_when { |a,b| a.match?(r) ^ b.match?(r) }.to_a
=> [["a"], ["b", "g"], ["e"], ["f"], ["i"]]
String#match? made its debut in Ruby v2.4. For earlier versions you could use (for example) !!(b =~ r), where !! converts a truthy/falsy value to true/false. That converstion is needed because the XOR operator ^ serves double-duty: it's a logical XOR when a and b in a^b are true, false or nil, and a bit-wise XOR when the operands are integers, such as 2^6 #=> 4 (2.to_s(2) #=> "10"; 6.to_s(2) #=> "110"; 4.to_s(2) #=> "100").
One more way to skin a cat
def contains_vowel(v)
v.count("aeiou") > 0
end
def split_by_substring_with_vowels(arr)
arr.chunk_while do |before,after|
!contains_vowel(before) & !contains_vowel(after)
end.to_a
end
split_by_substring_with_vowels(arr)
#=> [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
What it does:
passes each consecutive 2 elements
splits when either of them contain vowels
Example with your other Array
arr = ["1)", "dwr", "lyn,", "18,", "bbe"]
split_by_substring_with_vowels(arr)
#=> [["1)", "dwr", "lyn,", "18,"], ["bbe"]]
Further example: (if you want vowel containing elements in succession to stay in the same group)
def split_by_substring_with_vowels(arr)
arr.chunk_while do |before,after|
v_before,v_after = contains_vowel(before),contains_vowel(after)
(!v_before & !v_after) ^ (v_before & v_after)
end.to_a
end
arr = ["1)", "dwr", "lyn,", "18,", "bbe", "re", "rr", "aa", "ee"]
split_by_substring_with_vowels(arr)
#=> [["1)", "dwr", "lyn,", "18,"], ["bbe", "re"], ["rr"], ["aa", "ee"]]
This checks if before and after are both not vowels Or if they both are vowels
I might use chunk which splits an array everytime the value of its block changes. Chunk returns a list of [block_value, [elements]] pairs, I used .map(&:last) to only get the sub-lists of elements.
arr = ["a", "b", "g", "e", "f", "h", "i"]
def vowel?(x); %w(a e i o u).include?(x); end
arr.chunk{|x| vowel?(x)}.map(&:last)
=> [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
contains_vowel = ->(str) { !(str.split('') & %w|a e i o u|).empty? }
_, result = ["a", "b", "g", "e", "f", "h", "i"].
each_with_object([false, []]) do |e, acc|
cv, acc[0] = acc[0], contains_vowel.(e)
cv ^ acc.first ? acc.last << [e] : (acc.last[-1] ||= []) << e
end
result
#⇒ [["a"], ["b", "g"], ["e"], ["f", "h"], ["i"]]
What we do here:
contains_vowel is a lambda to check whether the string contains a vowel or not.
we reduce the input array, collecting the last value (contained the previously handled string the vowel or not,) and the result.
cv ^ acc.first checks whether it was a flip-flop of vowel on the last step.
whether is was, we append a new array to the result
whether is was not, we append the string to the last array in the result.

How to iterate over consecutive elements

I'm looking for a method that is similar to Array#combination, but the order matters.
Given this input:
array = ['a','b','c','d','e']
I'd like to get:
[['a','b','c'],['b','c','d'],['c','d','e']]
I'm trying to find the method that does this:
array = ['a','b','c','d','e']
x,a = 3,[]
until x > (ary.size) do
a += (0.upto(ary.size - x).map{|i| ary[i..(x-1)+i]} )
x += 1
end
The Enumerable documentation is your friend:
array = ['a','b','c','d','e']
array.each_cons(3).to_a
# => [["a", "b", "c"], ["b", "c", "d"], ["c", "d", "e"]]
each_cons(n) { ... }
Iterates the given block for each array of consecutive elements. If no block is given, returns an enumerator.

Ruby longest palindrome. Nested while loops

I am writing some code to find the longest palindrome in a string. I want to start at index 0 and then push the increasing length of the substring to an array:
ex:
string = "ababa"
[["a", "b"], ["a", "b", "a"], ["a", "b", "a", "b"], ["a", "b", "a", "b", "a"]]
It should then start on index 1 and do the same:
ex:
string = "ababa"
[["b","a"],["b","a","b"],["b","a","b","a"]
This should continue until the index is length -1 .However, the following code stops after it has gone through all iterations beginning with the first index and only returns:
[["a", "b"], ["a", "b", "a"], ["a", "b", "a", "b"], ["a", "b", "a", "b", "a"]]
What is the flaw in my logic? Code below
def longest_palindrome(s)
array = s.chars
start = 0
place = 1
output = []
while start < s.length - 1
while place < s.length
output << array[start..place]
place += 1
end
start += 1
end
return output
end
I believe this is what you are after:
def longest_palindrome(s)
arr = s.chars
output = []
(0...s.length).each do |start|
(start + 1...s.length).each do |place|
output << arr[start..place]
end
end
output
end
longest_palindrome("ababa")
=> [["a", "b"], ["a", "b", "a"], ["a", "b", "a", "b"], ["a", "b", "a", "b", "a"], ["b", "a"], ["b", "a", "b"], ["b", "a", "b", "a"], ["a", "b"], ["a", "b", "a"], ["b", "a"]]
Using iterators really simplifies things. Here is a more concise version:
def longest_palindrome(s)
output = (0...s.length).flat_map do |start|
(start + 1...s.length).map do |place|
s[start..place]
end
end
end
longest_palindrome("ababa")
=> ["ab", "aba", "abab", "ababa", "ba", "bab", "baba", "ab", "aba", "ba"]
A working, non-optimized, written on-the-fly 30 minutes, who knows how awfully slow longest palindrome finder:
def longest_palindrome(string, min_size = 2)
string = string.downcase # we will not be taking
return string if string == string.reverse # skip all calculaions of the passed string itself is a palindrome in original order
letters = string.chars # Convert string to array of bytes
combinations = [] # Initialize all letter combinations
(min_size..letters.size).each do |n| # min_size is the shortest length a palindrome is allowed to be, default 2
combinations.concat(letters.combination(n).to_a) # concat all combinations for n amount of characters in the string
end
palindromes = [] # Initialize array for all palindromes
combinations.each do |combo| # interate every combo
combo.size.times do # for every letter ordering is done via size of this letter combo
palindromes << combo.dup if combo == combo.reverse # add to list of palindromes if the combinations is the same backwards
combo.rotate! # rotate the letters for next order checking
end
end
palindromes.sort {|a, b| a.size <=> b.size }.last.join # sort the palidromes by length, take the biggest one, and return it as a full string
end
p longest_palindrome("racecar") #=> racecar
p longest_palindrome("applesauce") #=> pecep
p longest_palindrome("madam im adam") #=> mada m adam
p longest_palindrome("madamimadam") #=> madamimadam
but it works, sort of.
As you can see if sort of gets odd when spaces/puncuation are added to the mix.
You can always clean the string of it in the first line if need be.
Viva la algorithmless coding!

Nested loops in Ruby

I am trying to count the number of similar prefix beginnings to a string in Ruby. e.g; input "ababaa" should output 11;
ababaa = 6
babaa = 0
abaa = 3
baa = 0
aa = 1
a = 1
I have got as far as the code below, using a nested loop to go through each of the above as an array, however it looks as though Ruby is currently outputting the count of just the first Array object, "ababaa".
Solved, thanks :)
def string_suffix(string)
num = 0
ary = []
string.length.times do
ary << string[num..string.length]
num = num + 1
end
result = 0
ary.each do |x| # ["ababaa", "babaa", "abaa", "baa", "aa", "a"]
x.chars.each_with_index do |c,index|
break unless c == string[index]
result = result + 1
end
end
return result
end
I have looked far and wide and still cannot solve the issue, It looks like the (final, nested) array is breaking after the first iteration of the 'ary' Array and just returning that output.
You are returning the result while you are still in the loop. You need to move result = 0 out of the loop, and move the return result statement outside of the loop too. At the moment the function is going through the first iteration of the loop ("ababaa", for which all characters match), but you want result to equal the sum of all results.
Additionally, instead of doing:
count = 0
x.chars.each do |x|
if x == string[count]
count = count + 1
result = result + 1
else
count = count + 1
end
end
You could use the function each_with_index, to get
x.chars.each_with_index do |c,index|
if c == string[index]
result = result + 1
end
end
However, since you are trying to count how many characters in the substring are a prefix of string, you want to break when you first find a character c that is not equal to string[index], so that you don't end up counting extra characters. The loop then becomes:
x.chars.each_with_index do |c,index|
if c == string[index]
result = result + 1
else
break
end
end
I noticed you are returning the result inside your second loop, at the end. This means that after you've gone through the first item in your array the function returns just the result for the first item. Move your return statement to outside the loop.
As I understand, the problem is this: given a string s, for each i = 0..s.size-1, compute the number of leading characters of s[0..-i-1] that match the corresponding characters (i.e., at same offsets) of s[i..-1], and sum these s.size subtotals.
Here's a Ruby-like way to do that, using Enumerable#reduce (aka inject) and Enumerable#take_while:
str = "ababaa"
arr = str.chars
(0...arr.size).reduce(0) do |tot,i|
tot + arr[0..-i-1].zip(arr[i..-1]).take_while { |x,y| x == y }.size
end
#=> 11
The steps:
arr = str.chars
#=> ["a", "b", "a", "b", "a", "a"]
r = 0...arr.size
#=> 0...6
When the first element of r is passed to the block, the block variables are set to:
tot = 0
i = 0
The block calculation is therefore as follows:
a = arr[0..-i-1].zip(arr[i..-1])
#=> arr[0..-1].zip(arr[0..-1])
#=> arr.zip(arr)
#=> ["a", "b", "a", "b", "a", "a"].zip(["a", "b", "a", "b", "a", "a"])
#=> [["a", "a"], ["b", "b"], ["a", "a"], ["b", "b"], ["a", "a"], ["a", "a"]]
b = a.take_while { |x,y| x == y }
#=> [["a", "a"], ["b", "b"], ["a", "a"], ["b", "b"], ["a", "a"], ["a", "a"]]
tot + b.size
#=> 0 + 6
#=> 6
Note that this calculation will always equal arr.size for the first element of arr passed to the block.
When the next element of arr is passed to the block, the block variable i is set to 1. tot, which we just computed, equals 6. The block calculation is therefore:
a = arr[0..-i-1].zip(arr[i..-1])
#=> arr[0..-2].zip(arr[1..-1])
#=> ["a", "b", "a", "b", "a"].zip(["b", "a", "b", "a", "a"])
#=> [["a", "b"], ["b", "a"], ["a", "b"], ["b", "a"], ["a", "a"]]
b = a.take_while { |x,y| x == y }
#=> []
tot + b.size
#=> 6 + 0
#=> 6
The remaining calculations are similar. After all elements of arr have been sent to the block, reduce returns the value of tot.

Resources