Ruby. How to split a string element inside an array? - arrays

I have an array of arr=["abcd"]
Q1. Is there a simpler way to split the 'abcd' into arr=["a","b","c","d"] than the following:
arr=["abcd"]
arr_mod=[]
x=0
while x < arr[0].size
arr_mod << arr[0][x]
x +=1
end
puts "==>#{arr_mod}"
arr.split('') will not work.
Q2. Is there a method to convert arr=["abcd"] to the string of "abcd"?

arr.first.split('')
#=> ["a", "b", "c", "d"]
arr.first
#=> "abcd"

Q1:
This would give you some flexibility in case you ever needed a way to iterate over an array of more than one element:
arr = ['abcd']
arr = arr[0].split("")
#=> ["a", "b", "c", "d"]
Q2:
arr = ['abcd']
arr = arr[0]
#=> "abcd"

Simplest way is to do
arr.join("").chars
This turns the arr into one big string, then turns that string into an array of characters.
For your second question, just do arr.join(""), which will turn all the strings into the array into one big string.
For more information, check out Array#join and String#chars for more detail.

Q1:
arr.map(&:chars).flatten
#=> ["a", "b", "c", "d"]
Q2:
arr = arr[0]
#=> "abcd"

This is one way:
arr.join.split('') #=> ["a", "b", "c", "d"]

Related

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.

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!

Is there a Ruby Array method that returns two sub-arrays: one of specified size and another of the remaining contents?

I need to render the contents of the first 5 elements of an array and display "And X more" on a web page. Is there a built-in method on Array (or Enumerable) that easily separates one array into two sub-arrays: the first consisting of up to a fixed size and the second consisting of the array remainder?
I'm looking for one simple method call that will do this for me. Most of the methods that I looked at (like Enumerable#partition) use a logical condition to divide the array and don't supply the index to the block.
I just wrote the following code to do what I want. Please save me from myself and direct me to a method that already does it.
class Array
def bifurcate(size=length)
if size < 0
raise ArgumentError, "attempt to bifurcate using negative size"
end
remainder_size = length - size
if remainder_size < 0
remainder_size = 0
end
[
first(size),
last(remainder_size)
]
end
end
('a'..'g').to_a.bifurcate(2)
# => [["a", "b"], ["c", "d", "e", "f", "g"]]
('a'..'g').to_a.bifurcate(20)
# => [["a", "b", "c", "d", "e", "f", "g"], []]
('a'..'g').to_a.bifurcate()
# => [["a", "b", "c", "d", "e", "f", "g"], []]
('a'..'g').to_a.bifurcate(0)
# [[], ["a", "b", "c", "d", "e", "f", "g"]]
('a'..'g').to_a.bifurcate(-1)
# ArgumentError: attempt to bifurcate using negative size
Also, let me qualify that I want one simple method call to do what I want. Also consider that the starting array may contain duplicate values and this method needs to respect the original array and return duplicates.
You can use Enumerable#partition along with Enumerator#with_index method, as shown below:
size = 2
(1..6).partition.with_index { |_,i| i < size }
#=> [[1, 2], [3, 4, 5, 6]]
Alternatively, if your input array can be mutated, then, following will also do the trick
[array.shift(size), array]
[array.take(3), array.drop(3)]
# [["a", "b", "c"], ["d", "e", "f", "g"]]
Hope it helps :)
Use Array#[]:
[arr[0,size_of_first], arr[size_of_first..-1] || []]

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

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]

removing array brackets

I think its' silly question lol
I have below array
[['a','b','c'],['d','e','f']]
and want that array to be
['a','b','c'],['d','e','f']
which means i want to remove the first bracket.
Does that make sense?
Thanks in adv.
no, this doesn't make sense really, because ['a','b','c'],['d','e','f'] in this notation are two separate objects/arrays not inside any other data structure...
you could do an assignment, like :
a,b = [['a','b','c'],['d','e','f']]
and then
> a
=> ["a", "b", "c"]
> b
=> ["d", "e", "f"]
or better just iterate over the outer array (because you don't know how many elements it has):
input = [['a','b','c'],['d','e','f']]
input.each do |x|
puts "element #{x.inspect}"
end
=>
element ["a", "b", "c"]
element ["d", "e", "f"]
It doesn’t make sense. Do you mean a string manipulation?
irb(main):001:0> s = "[['a','b','c'],['d','e','f']]"
=> "[['a','b','c'],['d','e','f']]"
irb(main):002:0> s[1...-1]
=> "['a','b','c'],['d','e','f']"
Or, do you want to flatten an array?
irb(main):003:0> [['a','b','c'],['d','e','f']].flatten
=> ["a", "b", "c", "d", "e", "f"]

Resources