I am trying to do this test and there are bunch of solutions online and here but I first want to figure out why my solution is wrong even though it seems that it puts right results when I enter certain strings :
Here is what they are asking :
Write a method that takes in a string. Return the longest word in the
string. You may assume that the string contains only letters and
spaces.
You may use the String split method to aid you in your quest.
Here is my solution where I thought I could turn string into array, sort it from max length descending and then just print first element in that new string like this :
def longest_word(sentence)
sentence = sentence.split
sentence.sort_by! { |longest| -longest.length }
return sentence[0]
end
That doesn't seem to work obviously since their test gives me all false..here is the test :
puts("\nTests for #longest_word")
puts("===============================================")
puts(
'longest_word("short longest") == "longest": ' +
(longest_word('short longest') == 'longest').to_s
)
puts(
'longest_word("one") == "one": ' +
(longest_word('one') == 'one').to_s
)
puts(
'longest_word("abc def abcde") == "abcde": ' +
(longest_word('abc def abcde') == 'abcde').to_s
)
puts("===============================================")
So the question is why? And can I just fix my code or the idea is all wrong and I need to do it completely different?
str = "Which word in this string is longest?"
r = /[[:alpha:]]+/
str.scan(r).max_by(&:length)
#=> "longest"
This regular expression reads, "match one or more characters". The outer brackets constitute a character class, meaning one of the characters within the brackets must be matched.
To deal with words that are hyphenated or contain single quotes, the following is an imperfect modification1:
str = "Who said that chicken is finger-licken' good?"
r = /[[[:alpha:]]'-]+/
str.scan(r).max_by(&:length)
#=> "finger-licken'"
This regular expression reads, "match one or more characters that are a letter, apostrophe or hyphen". The outer brackets constitute a character class, meaning one of the characters within the brackets must be matched.
1 I've successfully used "finger-licken'" in scrabble.
I'd write it something like:
str = "Write a method that takes in a string"
str.split.sort_by(&:length).last # => "string"
Related
I'm working on an array containing Twitter handles such as:
array = ["#user1","#User2","#uSer3","#User4"]
I want to know how many handles start with a capital letter.
If the question is "how many in a collection" , then count could very well be the way to go.
The regular expression /[[:upper:]]/ has the benefit that it matches capital letters other than A-Z.
array = ["#user1","#User2","#uSer3","#User4"]
p array.count{|handle| handle[1].match?( /[[:upper:]]/ )} # => 2
Even though there's an accepted answer, I felt like it's worth mentioning that the same can be accomplished using #count instead of #inject:
array = ["#user1","#User2","#uSer3","#User4"]
capital_letters = ('A'..'Z')
array.count {|x| capital_letters.include?(x[1])}
#=> 2
If a block is given to the #count method, it counts the number of elements for which the block returns a true value. The block, in this case, evaluates to true if the second letter of the array x[1] is a capital letter from A to Z. This works under the assumption that every string in the array starts with a "#".
I used a regex to match # followed by a capital letter at the start of the string.
count is the most semantic function (thanks to #crenmo):
array.count {|e| e =~ /^#[A-Z]/}
select is useful if you'd like a list of matched elements:
array.select {|e| e =~ /^#[A-Z]/ }
Use [[:upper:]] instead of [A-Z] if you wish to match non-English uppercase letters (thanks to #CarySwoveland).
For reference, indexing into a string can be done with bracket notation (although I didn't wind up using this): str[0]
I am trying to return all words which have more than four letters in the below exercise.
def timed_reading(max_length, text)
var_b = text.split(" ")
var_b.map do |i|
if i.length >= max_length
return i
end
end
end
print timed_reading(4,"The Fox asked the stork, 'How is the soup?'")
# >> asked
I seem to get only one word.
If you want to filter a list and select only certain kinds of entries, use the select method:
var_b.select do |i|
i.length >= max_length
end
Where that's all you need.
The return i in the middle is confusing things, as that breaks out of the loop and returns a single value from the method itself. Remember that in Ruby, unlike others such as JavaScript, return is often implied and doesn't need to be spelled out explicitly.
Blocks don't normally have return in them for this reason unless they need to interrupt the flow and break out of the method itself.
You don't need to first extract all words from the string and then select those having at least four letters. Instead you can just extract the desired words using String#scan with a regular expression.
str = "The Fox asked the stork, 'How is the soup?'? Très bon?"
str.scan /\p{Alpha}{4,}/
#=> ["asked", "stork", "soup", "Très"]
The regular expression reads, "Match strings containing 4 or more letters". I've used \p{Alpha} (same as \p{L} and [[:alpha:]]) to match unicode letters. (These are documented in Regexp. Search for these expressions there.) You could replace \p{Alpha} with [a-zA-Z], but in that case "Très" would not be matched.
If you wish to also match digits, use \p{Alnum} or [[:alnum:]] instead. While \w also matches letters (English only) and digits, it also matches underscores, which you probably don't want in this situation.
Punctuation can be a problem when words are extracted from the string by splitting on whitespace.
arr = "That is a cow.".split
#=> ["That", "is", "a", "cow."]
arr.select { |word| word.size >= 4 }
#=> ["That", "cow."]
but "cow" has only three letters. If you instead used String#scan to extract words from the string you obtain the desired result.
arr = "That is a cow?".scan /\p{Alpha}+/
#=> ["That", "is", "a", "cow"]
arr.select { |word| word.size >= 4 }
#=> ["That"]
However, if you use scan you may as well use a regular expression to retrieve only words having at least 4 characters, and skip the extra step.
I am trying to call the first duplicate character in my string in Ruby.
I have defined an input string using gets.
How do I call the first duplicate character in the string?
This is my code so far.
string = "#{gets}"
print string
How do I call a character from this string?
Edit 1:
This is the code I have now where my output is coming out to me No duplicates 26 times. I think my if statement is wrongly written.
string "abcade"
puts string
for i in ('a'..'z')
if string =~ /(.)\1/
puts string.chars.group_by{|c| c}.find{|el| el[1].size >1}[0]
else
puts "no duplicates"
end
end
My second puts statement works but with the for and if loops, it returns no duplicates 26 times whatever the string is.
The following returns the index of the first duplicate character:
the_string =~ /(.)\1/
Example:
'1234556' =~ /(.)\1/
=> 4
To get the duplicate character itself, use $1:
$1
=> "5"
Example usage in an if statement:
if my_string =~ /(.)\1/
# found duplicate; potentially do something with $1
else
# there is no match
end
s.chars.map { |c| [c, s.count(c)] }.drop_while{|i| i[1] <= 1}.first[0]
With the refined form from Cary Swoveland :
s.each_char.find { |c| s.count(c) > 1 }
Below method might be useful to find the first word in a string
def firstRepeatedWord(string)
h_data = Hash.new(0)
string.split(" ").each{|x| h_data[x] +=1}
h_data.key(h_data.values.max)
end
I believe the question can be interpreted in either of two ways (neither involving the first pair of adjacent characters that are the same) and offer solutions to each.
Find the first character in the string that is preceded by the same character
I don't believe we can use a regex for this (but would love to be proved wrong). I would use the method suggested in a comment by #DaveNewton:
require 'set'
def first_repeat_char(str)
str.each_char.with_object(Set.new) { |c,s| return c unless s.add?(c) }
nil
end
first_repeat_char("abcdebf") #=> b
first_repeat_char("abcdcbe") #=> c
first_repeat_char("abcdefg") #=> nil
Find the first character in the string that appears more than once
r = /
(.) # match any character in capture group #1
.* # match any character zero of more times
? # do the preceding lazily
\K # forget everything matched so far
\1 # match the contents of capture group 1
/x
"abcdebf"[r] #=> b
"abccdeb"[r] #=> b
"abcdefg"[r] #=> nil
This regex is fine, but produces the warning, "regular expression has redundant nested repeat operator '*'". You can disregard the warning or suppress it by doing something clunky, like:
r = /([^#{0.chr}]).*?\K\1/
where ([^#{0.chr}]) means "match any character other than 0.chr in capture group 1".
Note that a positive lookbehind cannot be used here, as they cannot contain variable-length matches (i.e., .*).
You could probably make your string an array and use detect. This should return the first char where the count is > 1.
string.split("").detect {|x| string.count(x) > 1}
I'll use positive lookahead with String#[] method :
"abcccddde"[/(.)(?=\1)/] #=> c
As a variant:
str = "abcdeff"
p str.chars.group_by{|c| c}.find{|el| el[1].size > 1}[0]
prints "f"
This code capitalizes the first letter of each word in a string.
Eg "this is a sentence" becomes "This Is A Sentence".
def capitalize_words(string)
words = string.split(" ")
idx = 0
while idx < words.length
word = words[idx]
word[0] = word[0].upcase
words[idx] = word #this line of code can be made redundant, but why?
idx += 1
end
return words.join(" ")
end
In the while statement, I don't understand why the third line is unnecessary. The second line sets the first letter of a word to capital:
word[0] = word[0].upcase
how does the while statement know to refer back to the previous line
word = words[idx]
to put the new capitalised-letter word back into the words array? I thought that when codes are executed, it always works in a forward fashion, please let me know if this understanding is incorrect.
It's because word variable holds reference for object - the same object that is in words array. So if you modify this object, the object in array is modified also, because it's the same.
BTW what you're trying to do here can be done much easier:
string.split(' ').map(&:capitalize).join(' ')
As Stefan suggested: Keep in mind that capitalize not only converts first character to uppercase, but also converts all remaining chars to lowercase. If this is not what you want, you can also do:
string.split(' ').map { |word| word.slice(0, 1).upcase + word.slice(1..-1) }
or use Stefan's solution with regexp:
string.gsub(/\b\w/) { |ch| ch.upcase }
Keep in mind that \b in regexp will 'split' your word not only by spaces, but by any word boudary.
If you are only using ruby then use answer as per #Marek's answer :
string.split(' ').map(&:capitalize).join(' ')
and If you are using Ruby with Rails then use this:
"this is a sentence".titleize
I'm trying to take the string "xxxyyyzzz" and split it up into an array that groups the same letters. So I want the output to be ["xxx","yyy","zzz"]. I'm not sure why this code keeps on looping. Any suggestions?
def split_up(str)
i = 1
result = []
array = str.split("")
until array == []
if array[i] == array[i-1]
i += 1
else
result << array.shift(i).join("")
end
i = 1
end
result
end
puts split_up("xxxyyyzzz")
The looping is because your until condition never exits. You are incrementing i when the successive characters match, but at the end of the loop you are resetting i to 1.
If you edit this section and add this line:
until array == []
puts i # new line
Then you'll see that i is always 1, and the code keeps printing 1 forever.
Delete the line i = 1 line and you'll get the result you want.
Also, you may be interested in reading about the Ruby string scan method, and pattern matching and capture groups, and using look-ahead and look-behind zero-length assertions, which can match boundaries.
Here is how I would personally accomplish splitting a string at letter boundaries:
"xxxyyyzzz".scan(/(.)(\1*)/).map{|a,b| a+b }
=> ["xxx", "yyy", "zzz"]
The scan method is doing this:
. matches any character e.g. "x", and the parentheses capture this.
\1* matches the previous capture any number of time, e.g. "xx", and the parentheses capture this.
Thus $1 matches the first character "x" and $2 matches all the repeats "xx".
The scan block concatenates the first character and its repeats, so returns "xxx".
As mentioned above, this can be solved using scan like this:
def split_up(string)
repeat_alphabets = /(\w)(\1*)/
string.scan(repeat_alphabets).map do |match|
match[0] << match[1]
end
end
Explanation:
The regular expression matches repeating characters, but due to the construction of the regex matches occur as pairs of the alphabet and remaining repeated instances.
m[0] << m[1] joins the matches to form the required string.
map combines the string into an array and returns the array as it being the last statement.