Method to front capitalized words - ruby

I am trying to move capitalized words to the front of the sentence. I expect to get this:
capsort(["a", "This", "test.", "Is"])
#=> ["This", "Is", "a", "test."]
capsort(["to", "return", "I" , "something", "Want", "It", "like", "this."])
#=> ["I", "Want", "It", "to", "return", "something", "like", "this."]
The key is maintaining the word order.
I feel like I'm very close.
def capsort(words)
array_cap = []
array_lowcase = []
words.each { |x| x.start_with? ~/[A-Z]/ ? array_cap.push(x) : array_lowcase.push(x) }
words= array_cap << array_lowcase
end
Curious to see what other elegant solutions might be.

The question was changed radically, making my earlier answer completely wrong. Now, the answer is:
def capsort(strings)
strings.partition(&/\p{Upper}/.method(:match)).flatten
end
capsort(["a", "This", "test.", "Is"])
# => ["This", "Is", "a", "test."]
My earlier answer was:
def capsort(strings)
strings.sort
end
capsort(["a", "This", "test.", "Is"])
# => ["Is", "This", "a", "test."]
'Z' < 'a' # => true, there's nothing to be done.

def capsort(words)
words.partition{|s| s =~ /\A[A-Z]/}.flatten
end
capsort(["a", "This", "test.", "Is"])
# => ["This", "Is", "a", "test."]
capsort(["to", "return", "I" , "something", "Want", "It", "like", "this."])
# => ["I", "Want", "It", "to", "return", "something", "like", "this."]

def capsort(words)
caps = words.select{ |x| x =~ /^[A-Z]/ }
lows = words.select{ |x| x !~ /^[A-Z]/ }
caps.concat(lows)
end

Related

wrong number of arguments and hash issues

I am trying to make a method that counts the number of times it uses a word from a dictionary and is returned as a hash. Here's my code now:
def substrings(words, dictionary)
hash = {}
substrings.downcase!
dictionary.each do |substring|
words.each do |word|
if word.include? substring +=1
end
end
end
hash.to_s
end
dictionary = ["below", "down", "go", "going", "horn", "how", "howdy", "it", "i", "low", "own", "part", "partner", "sit"]
words = "below"
substrings(words, dictionary)
And I get this error:
wrong number of arguments (given 0, expected 2)
I'm looking for something like this:
=> {"below"=>1, "low"=>1}
I have tried multiple things but it never gives me that hash. I either get an undefined method error or this:
=> ["below", ["below", "down", "go", "going", "horn", "how", "howdy", "it", "i", "low", "own", "part", "partner", "sit"]]
Your error is caused by the line "substrings.downcase!" This is a recursive call to your substrings method which takes two arguments, and you are providing none. If this were not the case, you would still get an error, a stack overflow caused by the infinite recursion of this code.
This will produce the desired result, but I'm exchanging words in favor of word:
def substrings(word, dictionary)
word = word.downcase
dictionary.select { |entry| word.include?(entry.downcase) }
.group_by(&:itself)
.map { |k, v| [k, v.size] }.to_h
end
This results in:
>> dictionary = ["below", "down", "go", "going", "horn", "how", "howdy", "it", "i", "low", "own", "part", "partner", "sit"]
>> word = 'below'
>> substrings(word, dictionary)
=> {"below"=>1, "low"=>1}
And counts multiple copies of words, which although not explicitly stated, is presumably what you are after:
>> dictionary = ["below", "be", "below", "below", "low", "be", "pizza"]
>> word = 'below'
>> substrings(word, dictionary)
=> {"below"=>3, "be"=>2, "low"=>1}
You can use #reduce:
def substrings(sentence, dictionary)
sentence = sentence.downcase
dictionary.reduce(Hash.new(0)) do |counts,word|
counts[word] +=1 if sentence.include?(word.downcase)
counts
end
end
dictionary = ["below", "down", "go", "going", "horn", "how", "howdy", "it", "i", "low", "own", "part", "partner", "sit"]
sentence = "below"
substrings(sentence, dictionary) #=> {"below"=>1, "low"=>1}
Or #each:
def substrings(sentence, dictionary)
sentence = sentence.downcase
counts = Hash.new(0) # Makes the default value `0` instead of `nil`
dictionary.each do |word|
if sentence.include?(word.downcase)
counts[word] += 1
end
end
counts
end
dictionary = ["below", "down", "go", "going", "horn", "how", "howdy", "it", "i", "low", "own", "part", "partner", "sit"]
sentence = "below"
substrings(sentence, dictionary) #=> {"below"=>1, "low"=>1}

Ruby : Split string on boundaries

I have a string of arbitrary characters, some of which are digits. I would like to break the strings into fields consisting of digits and non-digits. For example, if my string has the value 'abc34d-f9', I would like to get an array
['abc','34','d-f','9']
I'm nearly there, using look-behind and look-ahead expressions:
s.split(/( (?<=\D)(?=\d) | (?<=\d)(?=\D) )/x)
This splits on transitions between boundaries digit->nondigit and vice versa. However, I also get empty elements, i.e. this would return
['abc','','34','','d-f','','9']
Of course it is trivial to filter out the nullstrings from the array. I just wonder: Why do I get them, and how can I do it better?
Use string.scan function to return an array of matched strings.
> 'abc34d-f9'.scan(/\D+|\d+/)
=> ["abc", "34", "d-f", "9"]
\D+ matches one or more non-digit characters where \d+ matches one or more digit characters.
Your regex also works fine if you remove the capturing group. Because capturing group would also return the delimiter(boundary on which the input string was splitted) to the final output.
> 'abc34d-f9'.split(/(?<=\D)(?=\d)|(?<=\d)(?=\D)/)
=> ["abc", "34", "d-f", "9"]
> 'abc34d-f9'.split(/ (?<=\D)(?=\d) | (?<=\d)(?=\D) /x)
=> ["abc", "34", "d-f", "9"]
Though I prefer #AvinashRaj's solution, it's always fun (and sometimes often instructive) to try to find other ways:
str = 'abc34d-f9'
a = str.split(/(\d+)/) #=> ["abc", "34", "d-f", "9"]
a.shift if a.first.empty? #=> nil
a #=> ["abc", "34", "d-f", "9"]
a = str.split(/(\D+)/) #=> ["", "abc", "34", "d-f", "9"]
a.shift if a.first.empty? #=> ""
a #=> ["abc", "34", "d-f", "9"]
str.each_char.chunk { |c| !!(c =~ /\d/) }.map { |_,a| a.join }
#=> ["abc", "34", "d-f", "9"]
str[1..-1].each_char.with_object([str[0]]) { |c,a|
((c + a.last[0]) =~ /\d{2}|\D{2}/) ? a.last << c : a << c }
#=> ["abc", "34", "d-f", "9"]
(Ruby 2.2)
str.each_char.slice_when { |a,b| (a+b) =~ /\d\D|\D\d/ }.map(&:join)
#=> ["abc", "34", "d-f", "9"]

Ruby separating an array of strings by checking whether or not the object inherits from a certain class

I have an array of strings that I read from a file x
I have an empty array y
Some string objects are integers
How do I separate the integers from the strings, specifically by using a call to_a?
Right now i'm trying
x.each do |s|
if s.to_i.is_a?(Integer)
y << s
end
end
but this just converts everything to an integer and stuffs it in y, is there a way to see if an object is truly from the Integer class?
Edit add sample input/output
x = [ "This", "is", "a", "random", "amalgamation", "of", "text", "and", "a",
"bunch", "of", "numbers", "111113087403957304739703975", "how", "can", "I",
"read", "this", "in." ]
y = [ 111113087403957304739703975 ]
x = [ "This", "is", "a", "random", "amalgamation", "of", "text", "and", "a",
"bunch", "of", "numbers", "111113087403957304739703975", "how", "can", "I",
"read", "this", "in." ]
y = [ 111113087403957304739703975 ]
def extract_integers(array)
array.select { |v| v.match(/\A\d+\z/) }.map(&:to_i)
# or (simpler, as suggested by #theTinMan)
array.reject { |v| v[/\D/] }.map(&:to_i)
end
p extract_integers(x) #=> [111113087403957304739703975]
p extract_integers(x) == y #=> true
s.match(/^\d+$/) will match a string containing only numbers, so you can use this to test your strings against
You might use Enumerable#grep:
arr = %w[9 cats on 33 hot tin roofs]
#=> ["9", "cats", "on", "33", "hot", "tin", "roofs"]
arr.grep /^\d+$/
#=> ["9", "33"]
arr.grep(/^\d+$/).map(&:to_i)
#=> [9, 33]
x.each do |s|
begin
Integer(s)
rescue ArgumentError
else
y << s
end
end
If applied on a string that doesn't parse as an integer, Integer() raises an ArgumentError. You can use this to find integer strings.
It's always interesting, and useful to run benchmarks:
require 'fruity'
x = [ "This", "is", "a", "random", "amalgamation", "of", "text", "and", "a",
"bunch", "of", "numbers", "111113087403957304739703975", "how", "can", "I",
"read", "this", "in." ]
def extract_integers(array)
array.select { |v| v.match(/\A\d+\z/) }.map(&:to_i)
end
def extract_integers_reject(array)
array.reject { |v| v[/\D/] }.map(&:to_i)
end
compare do
use_exception {
y = []
x.each do |s|
begin
Integer(s)
rescue ArgumentError
else
y << s.to_i
end
end
y
}
use_extract_integers {
extract_integers(x)
}
use_extract_integers_reject {
extract_integers_reject(x)
}
end
Running that results in the following on my machine:
Running each test 256 times. Test will take about 1 second.
use_extract_integers_reject is faster than use_extract_integers by 30.000000000000004% ± 10.0%
use_extract_integers is faster than use_exception by 6x ± 0.1
Note, y << s was changed to y << s.to_i to make the outputs all match.
I'd probably simplify the code using the ArgumentError rescue like this:
x.each do |s|
begin
y << Integer(s)
rescue ArgumentError
end
end

Ruby search for word in string

Given input = "helloworld"
The output should be output = ["hello", "world"]
Given I have a method called is_in_dict? which returns true if there's a word given
So far i tried:
ar = []
input.split("").each do |f|
ar << f if is_in_dict? f
// here need to check given char
end
How to achieve it in Ruby?
Instead of splitting the input into characters, you have to inspect all combinations, i.e. "h", "he", "hel", ... "helloworld", "e", "el" , "ell", ... "elloworld" and so on.
Something like this should work:
(0..input.size).to_a.combination(2).each do |a, b|
word = input[a...b]
ar << word if is_in_dict?(word)
end
#=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ar
#=> ["hello", "world"]
Or, using each_with_object, which returns the array:
(0..input.size).to_a.combination(2).each_with_object([]) do |(a, b), array|
word = input[a...b]
array << word if is_in_dict?(word)
end
#=> ["hello", "world"]
Another approach is to build a custom Enumerator:
class String
def each_combination
return to_enum(:each_combination) unless block_given?
(0..size).to_a.combination(2).each do |a, b|
yield self[a...b]
end
end
end
String#each_combination yields all combinations (instead of just the indices):
input.each_combination.to_a
#=> ["h", "he", "hel", "hell", "hello", "hellow", "hellowo", "hellowor", "helloworl", "helloworld", "e", "el", "ell", "ello", "ellow", "ellowo", "ellowor", "elloworl", "elloworld", "l", "ll", "llo", "llow", "llowo", "llowor", "lloworl", "lloworld", "l", "lo", "low", "lowo", "lowor", "loworl", "loworld", "o", "ow", "owo", "owor", "oworl", "oworld", "w", "wo", "wor", "worl", "world", "o", "or", "orl", "orld", "r", "rl", "rld", "l", "ld", "d"]
It can be used with select to easily filter specific words:
input.each_combination.select { |word| is_in_dict?(word) }
#=> ["hello", "world"]
This seems to be a task for recursion. In short you want to take letters one by one until you get a word which is in dictionary. This however will not guarantee that the result is correct, as the remaining letters may not form a words ('hell' + 'oworld'?). This is what I would do:
def split_words(string)
return [[]] if string == ''
chars = string.chars
word = ''
(1..string.length).map do
word += chars.shift
next unless is_in_dict?(word)
other_splits = split_words(chars.join)
next if other_splits.empty?
other_splits.map {|split| [word] + split }
end.compact.inject([], :+)
end
split_words('helloworld') #=> [['hello', 'world']] No hell!
It will also give you all possible splits, so pages with urls like penisland can be avoided
split_words('penisland') #=> [['pen', 'island'], [<the_other_solution>]]

What doesn't e.upcase return upper case words

I wanted to upper-case an array but got this behaviour:
=> ["this", "set", "of", "words", "is", "in", "a", "certain", "order"]
for this:
%w[this set of words is in a certain order].each {|e| e.upcase}
Why were the words NOT upper-cased?
(ignoring actual ordering right now dessite the words while I resolve this issue).
String#upcase returns a new string value, it doesn't modify the receiver. Use String#upcase! to get the behavior you want, or use map to produce a new array of the upcased values.
%w[this set of words is in a certain order].each { |e| e.upcase! }
up_words = %w[this set of words is in a certain order].map(&:upcase)
irb> %w[this set of words is in a certain order].map {|e| e.upcase}
=> ["THIS", "SET", "OF", "WORDS", "IS", "IN", "A", "CERTAIN", "ORDER"]
each throws away all the results, map collects all the results in a new array for you.
You are not mutating the input array. Although each is actually upcased while iterating, the original array will be returned unchanged. Use upcase! instead:
# Modifies the array in place and returns the modified version:
>> %w[this set of words is in a certain order].each {|e| e.upcase!}
=> ["THIS", "SET", "OF", "WORDS", "IS", "IN", "A", "CERTAIN", "ORDER"]
# Assign it to a variable to get the up-cased array:
up_cased = %w[this set of words is in a certain order].each {|e| e.upcase!}
up_cased
# => ["THIS", "SET", "OF", "WORDS", "IS", "IN", "A", "CERTAIN", "ORDER"]
If you were to print them in the each, they would have been upcased, but the original unmutated array was returned.
# Calls upcase for proof, but the original array is still returned:
>> %w[this set of words is in a certain order].each {|e| puts e.upcase}
THIS
SET
OF
WORDS
IS
IN
A
CERTAIN
ORDER
=> ["this", "set", "of", "words", "is", "in", "a", "certain", "order"]
It is a little easier to see if you operate on a variable:
arr = %w[this set of words is in a certain order]
# upcase, but don't modify original
arr.each {|e| e.upcase}
arr.inspect
# ["this", "set", "of", "words", "is", "in", "a", "certain", "order"]
# now modify in place with upcase!
arr.each {|e| e.upcase!}
arr.inspect
# ["THIS", "SET", "OF", "WORDS", "IS", "IN", "A", "CERTAIN", "ORDER"]

Resources