Im try to isolate the white space in ruby sentences - arrays

I am attempting to place all the characters of a string into its own index in an array and also am trying to replace " " (spaces) with 0's. The error I'm getting is that is says
?wrong number of arguments (given 0, expected 1)
but I'm not sure how to make include(' ') work.
Here is my code:
def findMe(words)
x = 0
convert = []
while x < words.length
if words[x].is_a? String && words[x].include? != " "
convert << words[x]
else
convert << 0
end
x = x + 1
end
p convert
end
findMe('Words and stuff.')
Desired Output: ["W", "o", "r", "d", "s", 0, "a", "n", "d", 0, "s", "t", "u", "f", "f", "."]

You're getting the "wrong number of arguments" error here:
words[x].include? != " "
You can quickly fix this by replacinng it with:
!words[x] == " "
A better way to do the whole thing would be:
words.gsub(" ", "0").chars

Use Array#chars.
'Words and stuff.'.chars.map { |c| c == " " ? "0" : c }
#=> ["W", "o", "r", "d", "s", "0", "a", "n", "d", "0", "s", "t", "u", "f", "f", "."]

Related

Swift Array - Difference between "Int.random(in: 0...25)" and "randomElement()"

I recently started learning swift via an online course.
I was given the Task to generate a passwort out of a given Array containing characters.
We learned mainly two code examples to randomly choose one.
variable[Int.random(in: 0...25)]
variable.randomElement()
Both work just fine when pulling out one single element out of an array but only "variable[Int.random(in: 0...25)" when combined multiple times with a plus (+).
Why is that?
I looked up the documentation but couldn't find an answer
https://developer.apple.com/documentation/swift/array/2994747-randomelement
Explanation:
This code works:
let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
//The number of letters in alphabet equals 26
var password = alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)] + alphabet[Int.random(in: 0...25)]
print(password)
This code does not work, because "randomElement()" gets grey after combining multiple with plus (why?)
let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
//The number of letters in alphabet equals 26
var password = alphabet.randomElement() + alphabet.randomElement() + alphabet.randomElement() + alphabet.randomElement() + alphabet.randomElement() + alphabet.randomElement()
print(password)
Edit:
Thanks for the fast explanation guys !
The difference is that randomElement returns an optional string ( String?), as opposed to the subscript that returns a non-optional. Why does randomElement return an optional string? Well, what if the array is empty?
And Swift can't figure out how to add 2 optional strings (let alone 6! So it just gives up). One way to fix this is to force-unwrap the return values of randomElement:
let password = alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()!
We know the array is not empty, so we can safely force-unwrap here.
Arguably, randomElement is the better method to use here, because it forces you to think about the situation where the array is empty, and handle it accordingly. The first approach with subscripts doesn't have checks for whether the array is empty, or whether the indices are correct, etc.
This is because of the different return type between the two approaches.
Indexing an array of strings return, as you would expect, the String at that index.
However the .randomElement() function has a different signature: it return an optional element of the sequence, in your case an optional string (String?).
The '+' operator is defined for strings, but not for optional Strings. To add together the elements returned from .randomElement() you would need to unwrap them first. Given you have a closed sequence you it would be safe to force unwrap them with '!':
var password = alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()! + alphabet.randomElement()!
Instead of writing many times the same code, try some loops:
let alphabet = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
var i = 0
var temp = ""
//The number of letters in alphabet equals 26
while i < 6 {
temp = temp + alphabet[Int.random(in: 0...25)]
i += 1
}
let password = temp
print(password)
beginner in swift with below solution
let passwordChrt:Array = [
"A", "a", "B", "b", "C" , "c", "D", "d", "E", "e", "F", "f", "G", "g", "H", "h",
"I", "i", "J", "j", "K", "k", "L", "l", "M", "m","N", "n", "O", "o", "P", "p",
"Q", "q", "R", "r", "S", "s", "T", "t", "U", "u", "V", "v", "W", "w","X", "x", "Y",
"y", "Z", "z", 1, 2, 3, 4, 5, 6, 7 , 8 ,9, 0, "!", "#", "#", "$", "%", "^", "&", "*"] as [Any]
var password:String = ""
passwordChrt.shuffled()
for _ in passwordChrt {
if password.count < 6 {
password.append("\(passwordChrt.randomElement() ?? <#default value#>)")
}
}
print(password)
Updated, newer version:
func randomPassword(length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyz"
return String((0..<length).map { _ in letters.randomElement()! })
}
print(randomPassword(length: 6)) // e.g. output: "deckro"

Parsing string to an array of strings in Ruby

I have a string in this format:
"dataA\r\r\n" + "dataB\r\r\n" + "dataC\r\r\n" + "dataD"
The last data doesn't have "\r\r\n".
I would like to parse it and change to it an array of strings:
["dataA", "dataB", "dataC", "dataD"]
I am wondering what is the best way to do this.
You could split your concatenated string by passing \r\r\n which is a common point between each value:
a = "dataA\r\r\n" + "dataB\r\r\n" + "dataC\r\r\n" + "dataD"
p a.split(/\r\r\n/)
# => ["dataA", "dataB", "dataC", "dataD"]
str = "dataA\r\r\n" + "dataB\r\r\n" + "dataC\r\r\n" + "dataD"
#=> "dataA\r\r\ndataB\r\r\ndataC\r\r\ndataD"
str.split
#=> ["dataA", "dataB", "dataC", "dataD"]
See the 4th paragraph of the doc for String#split. Ruby's definition of "whitespace" is given in the doc for String#strip. For
str = "a" + "b\t\t" + "c\n\n\n" + "d\v\v" + "e\f" + "f\r\r" + "g " + "h"
str.split
#=> ["ab", "c", "d", "e", "f", "g", "h"]
is therefore equivalent to
str.split(/[\t\n\v\f\r \0]+/)
#=> ["ab", "c", "d", "e", "f", "g", "h"]
Search for "Backslash Notation" here for definitions of these backslash characters: horizontal tab, line feed, vertical tab, form feed, carriage return, space.

Select two elements from an array in Ruby

Suppose there is an array like this one:
list = ["a", "a", "a", "b", "b", "c", "d", "e", "e"]
We want to create a cycle where every next element is different from the previous element and the first element is different from the last element.
required = ["a", "b", "a", "b", "a", "c", "e", "d", "e"]
How is this done in ruby?
def create_cycle
temp = Array.new($input)
i, j, counter = 0
while i == 0
while (counter != $input.length)
j = rand(1..$input.length-1).floor
unless !($input[i][0].to_s.eql?$input[j][0])
$solution.push($input[i])
$solution.push($input[j])
puts input[i], input[j]
$input.delete_at(i)
$input.delete_at(j)
counter = counter + 1
end
end
end
end
I'm trying to learn this. Thank you for your help.
Additional notes:
The elements a, b, c, d, e represent special format strings, where
a certain property is common among them, thus the first element "a"
shares a property with the next element "a" but is not equivalent to
the first.
In the case it isn't possible to create a cycle, then, it is enough to raise a flag in command line.
I might do it like this:
>> list = [a, a, a, b, b, c, d, e, e]
>> list.sort.each_slice((list.size/2.0).round).reduce(:zip).flatten.compact
=> [a, c, a, d, a, e, b, e, b]
The general method is to:
sort the list, so all identical members are adjacent
divide the list in half from the middle
interleave the two halves together
Assuming you do not care about the order being the same as in the original array, and it is ok to have duplicates if there is no way, and also assuming the list is presorted, here is one approach - it just keeps adding elements from the beginning and end of the list till there are no elements left:
def interleaver list
result = []
el = list.first
while(el)
el = list.shift
if el
result << el
else
return result
end
el = list.pop
if el
result << el
else
return result
end
end
result
end
> a = 'a'
> b = 'b'
> c = 'c'
> d = 'd'
> e = 'e'
> list = [a, a, a, b, b, c, d, e, e]
> interleaver(list)
=> ["a", "e", "a", "e", "a", "d", "b", "c", "b"]
But if such interleaving is not possible, you will get duplicates:
> list = [a, a, a, b]
> interleaver(list)
#=> ["a","b","a","a"]
You can obtain such a string, or demonstrate that no such string exists, with the following recursive method.
Code
def doit(remaining, partial=[])
first_partial, last_partial = partial.first, partial.last
if remaining.size == 1
return ([first_partial, last_partial] & remaining).empty? ?
partial + remaining : nil
end
remaining.uniq.each_with_index do |s,i|
next if s == last_partial
rem = remaining.dup
rem.delete_at(i)
rv = doit(rem, partial + [s])
return rv if rv
end
nil
end
Examples
list = %w| a a b |
#=> ["a", "a", "b"]
doit list
#=> nil
The above demonstrates that the three elements of list cannot be permuted to satisfy the two ordering requirements.
list = %w| a a a b b c d e e |
#=> ["a", "a", "a", "b", "b", "c", "d", "e", "e"]
doit list
#=> ["a", "b", "a", "b", "c", "b", "e", "d", "e"]
This took 0.0042 second to solve on a newish MacBook Pro.
list = %w| a a a a a a a b b c d e e f f f g g g g h i i i i j j |
#=> ["a", "a", "a", "a", "a", "a", "a", "b", "b", "c", "d", "e", "e",
# "f", "f", "f", "g", "g", "g", "g", "h", "i", "i", "i", "i", "j", "j"]
doit list
#=> ["a", "b", "a", "b", "a", "b", "a", "b", "c", "b", "d", "e", "f",
# "e", "f", "g", "f", "g", "h", "g", "h", "i", "j", "i", "j", "i", "j"]
This took 0.0059 seconds to solve.
Out of curiosity, I then tried
list = (%w| a a a a a a a b b c d e e f f f g g g g h i i i i j j |).shuffle
#=> ["a", "c", "f", "b", "d", "i", "a", "a", "i", "a", "a", "g", "g",
# "a", "g", "i", "j", "b", "h", "j", "e", "e", "a", "g", "f", "i", "f"]
doit list
#=> ["a", "c", "f", "b", "d", "i", "a", "i", "a", "g", "a", "g", "a",
# "g", "i", "g", "j", "b", "h", "j", "e", "a", "e", "g", "f", "i", "f"]
This took a whooping 1.16 seconds to solve, suggesting that it may be desirable to pre-sort list (doit(list.sort)) if, of course, list is sortable.

How can I delete any items between two marker elements in an array?

I'm trying to find a way to remove any elements in an array that fall between two "markers", but there are a few quirks. To give a proper spec, the function I'm making is supposed to do this:
Remove any elements from the earliest start marker S to the earliest end marker E after the S, or the final element if there is none. Repeat this until there are no Ss left. Remove any remaining Es.
For example, if I had an array containing the following:
This is my current code:
# if the starting token is `1` and the ending one is `2`:
while clearing.include? 1
from = clearing.index(1)
to = clearing[from..-1].index(2) + from
clearing.slice!(from..to)
end
clearing.delete(2)
Which, when run with clearing set to:
["a", "b", "c", "d", "e", "f", 1, "g", "h", "i", "j", 1, "k", 2, "l", 2, 2, "m", "n", "o", "p", "q", "r", "s", 1, "t", "u", "v", "w", "x", 1, "y", "z"]
properly returns
["a", "b", "c", "d", "e", "f", "l", "m", "n", "o", "p", "q", "r", "s"]
Online test
It works, but it's ugly, and I'm fairly sure there's a more idiomatic way to do it. I can't find it, though, or think of it, so I'm asking here: Is my code the only (sane) way to do what I'm trying to?
This is, unfortunately, a severe case of the XY problem -- the specific task I'm trying to accomplish is removing comments from a string. I could do this with a fairly simple regex (/#.*?$/m) if I had the input string, but because it's a class assignment, I have to delete from anything starting with # to the :newline token in an array of them. Please don't suggest "This is weird, why not try solving the overall problem a different way" -- I know it's weird. I wish I could.
Overall, I think any solution is going to be as elegant as yours. The only thing I can think of is that you could make it faster by iterating over each character only once:
i = 0
loop do
break if i >= clearing.length
break if clearing[i] == 1
i += 1
end
loop do
break if i >= clearing.length
val = clearing.delete(i)
break if val == 2
end
Which is definitely less elegant.
Ruby's fairly obscure "flip-flop" operator could be used here. I'm not recommending that it be used, just sayin'.
clearing.reject { |e| (e==1..e==2) ? true : false }.reject { |e| e==2 }
#=> ["a", "b", "c", "d", "e", "f", "l", "m", "n", "o", "p", "q", "r", "s"]
The first block returns false until 1 is detected. It then returns true for the 1 and continues to return true until 2 is detected. It returns true for the 2, but then returns false until the next (if any) 1 is detected, and so on. Hence, the name "flip-flop". The example often given for the flip-flop operator is reading sections of a file that are delimited with start/end markers.
It may seem that (e==1..e==2) ? true : false could be simplified to (e==1..e==2), but that is not the case, as the latter expression is treated as a normal range. Flip-flops must have a conditional form.
Replace both rejects with reject! if clearing is to be changed in place.

Comparing string with array

I am trying to compare a string variable to an element of a string array using a for loop in visual basic. I am comparing a user-entered string variable to an array with the lowercase alphabet, in order. I have some logical mistake because my "count" variable is always on 25 for some reason, and therefore it always says "Sorry, Try again" unless the user types a Z. Please help!
Dim lower() As String = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
For count As Integer = 0 To 25
input = txtInput.Text
input = input.ToLower
If input.Equals(lower(count)) Then
txtResult.Text = "Correct"
Else
txtResult.Text = "Sorry, Try again"
End If
Next
The problem is that you should exit the loop (with exit for) after you find a match. Otherwise, any mismatched characters will reset txtResults.Text to "Sorry, Try again." For example, when you enter "f", txtResults.Text is set to "Correct". But when you get to g, currently, it changes txtResults.Text to "Sorry, Try again.", and h, i, etc.
This is a good exercise in programming, but there is a shortcut you can use:
lower.contains(input.lower)
Info:
http://msdn.microsoft.com/en-us/library/dy85x1sa.aspx
Welcome to StackOverflow!
The reason you get "Correct" result only if you type "z" is that "z" is the last item of the array. If you type "y", the result will be correct for count = 24 (lower(24) = "y"), but at the next step it compares "y" with lower(25), which is actually "z". So txtResult.Text will be overwritten by "Sorry, Try again".
As I get your task correctly, you want to check if the input string is exists in the array. For that purpose you may use Array.Contains method:
Dim lower() As String = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"}
Dim input As String = txtInput.Text
If (lower.Contains(input)) Then
txtResult.Text = "Correct"
Else
txtResult.Text = "Sorry, Try again"
End If

Resources