Staircase Problem Swift print "#" n and n-1 times - swift

Attempting to do the Staircase problem on Hackerrank and came up with a solution such as this;
import Foundation
func staircase(n: Int) -> Void {
var tag = "#"
var i = 0
while i < (n) {
print( tag)
tag += "#"
i = i + 1
}
}
expected output
my output
I understand that the difference is that the 7th line is empty and thats why I am getting an error. But dont quite understand the logic behind getting that extra line.

The terminator for print is a newline ("\n") by default.
To avoid newline
print(tag, terminator: "")

Hope this might help someone
for index in 1...n {
let counter = n - index
if index != 1 {
print()
}
for i in 1...n {
if counter < i {
print("#", terminator: "")
}
else {
print(" ", terminator: "")
}
}
}

Related

Algorithm on finding all 4 letter words in a string - where's the last item?

Posting a question here as ~find all ~4 letter words in a string ~algorithm site:stackoverflow.com google did not return any positive results.
The problem:
Write a function that takes a string of words and returns the number of 4 letter ones. The input argument 'sentence' is a string with words separated by spaces without punctuation.
So far I have a code like this:
func fourLetters(sentence: String) -> Int {
var targetNames = 0
var letterCount = 0
for letter in sentence {
if letter != " " {
letterCount += 1
} else {
print ("space found") // tech line
print (letterCount) // tech line
if letterCount == 4 {
targetNames += 1
letterCount = 0
}
letterCount = 0
}
}
print(targetNames) // tech line
return targetNames
}
The issue:
This algorithm now does not take into account the last part of the string giving the invalid number of 4 letter words. Consider we have the sentence: "Good Night Lil Peep" would return 1, although there are obviously two 4 teller words. What am I missing? Seems like the loop completely ignores the last word.
repl.it link for convenience and runs: https://repl.it/#DmitryAksyonov/4-lettered-names
Thank you for the help!
Regards
func findWords(ofLenght lenght: Int, in string: String) -> [Substring] {
let words = string.split{ $0.isWhitespace }
return words.filter { $0.count == lenght }
}
let input = "abcd word some string"
let result = findWords(ofLenght: 4, in: input)
print(result.count)
Output: 3
The problem is that the incrementation code for targetNames is encountered only if you find a space in the input string, which is not the case at the end of the string. You may be lucky if the last character of the string is a space.
So your code will fail even in the case where your sentence contains just one 4-letter word.
A possible solution is that you modify the condition of your first if statement by adding another condition to it which returns false if the loop has reached the end of the string, so that the else part of your code will run at that time and check if that last word is a 4-letter word.
Your algorithm doesn’t work because you don’t check for a 4-letter word at the end of the text.
You have to add another else clause and an index to check for end of text.
Of course there are more efficient ways to do that, it's just the answer to the question why the last item is not considered.
func fourLetters(sentence: String) -> Int {
var targetNames = 0
var letterCount = 0
var index = sentence.startIndex
for character in sentence {
sentence.formIndex(after: &index)
if character == " " { // check space
print ("space found") // tech line
print (letterCount) // tech line
if letterCount == 4 {
targetNames += 1
}
letterCount = 0
} else if index == sentence.endIndex { // check end of text
print ("end of text found") // tech line
letterCount += 1 // increment letterCount
if letterCount == 4 {
targetNames += 1
}
} else {
letterCount += 1
}
}
print(targetNames) // tech line
return targetNames
}
fourLetters(sentence: "Good Night Lil Peep") // 2

Disable Print("") In Swift 4, Xcode 10

I have Tried Many of Code But Could not disable Print() in Swift 4.
Can it can be disable?
Thanks
func print(items: Any..., separator: String = " ", terminator: String = "\n") {
#if DEBUG
var idx = items.startIndex
let endIdx = items.endIndex
repeat {
Swift.print(items[idx], separator: separator, terminator: idx == (endIdx - 1) ? terminator : separator)
idx += 1
}
while idx < endIdx
#endif
}
Code wise it's working as expected, your problem probably lies somewhere else,
and i think it's the scope of the function, Swift functions are declared with internal access modifier by default, you can try to change the position of this function into a separated file, calling it PublicUtility.swift for example.
and place your function there with access modifier public so would it be like this .
public func print(items: Any..., separator: String = " ", terminator: String = "\n") {
#if DEBUG
var idx = items.startIndex
let endIdx = items.endIndex
repeat {
Swift.print(items[idx], separator: separator, terminator: idx == (endIdx - 1) ? terminator : separator)
idx += 1
}
while idx < endIdx
#endif
}
Note : if you're calling your function and not the Swift.print, the
color of it should be different, like you're calling your own function
not the default one.

Better way to find occurrence amount of a certain character in a string

I'm using this to find the number of occurrences in a character of a string
String(appWindow.title.count - appWindow.title.replacingOccurrences(of: "x​", with: String()).count)
Is there a way to do it with a simpler command?
I tried to split it but it always says 1 even when the char isn't there.
One possible solution:
let string = "xhjklghxhjkjjklxjhjkjxx"
print(string.filter({ $0 == "x" }).count)
// prints: 5
You could use reduce, it increments the result($0) if the character($1) is found
let characterCount = appWindow.title.reduce(0) { $1 == "x" ? $0 + 1 : $0 }
Why can you simply do something like this?
let str = "Hello, playground"
let characters = CharacterSet(charactersIn: "o")
var count = 0
for c in str.unicodeScalars {
if characters.contains(c) {
count += 1
}
}
print("there are \(count) characters in the string '\(str)'")
But, as #Leo Dabus pointed out, that would only work for simple Unicode characters. Here's an alternative that would work for counting any single character:
for c in str {
if c == "o" {
count += 1
}
}
great responses
i went with
appWindow.title.components(separatedBy: "​x").count - 1

Swift 3/4 dash to camel case (Snake to camelCase)

I am trying to perform a simple dash to camel case so:
"this-is-my-id" will become "thisIsMyId" in swift 3 (or 4).
No matter what I do I can't find an elegant enough way to do it..:
The following doesn't work:
str.split(separator: "-").enumerated().map { (index, element) in
return index > 0 ? element.capitalized : element
}.reduce("", +)
It cries about all bunch of stuff. I am sure there is a simple enough way... Anyone?
Your code is almost correct. The following is the most readable implementation I have found:
let str: String = "this-is-my-id"
let result = str
.split(separator: "-") // split to components
.map { String($0) } // convert subsequences to String
.enumerated() // get indices
.map { $0.offset > 0 ? $0.element.capitalized : $0.element.lowercased() } // added lowercasing
.joined() // join to one string
print(result)
Just a better implementation of #sulthan's answer with Swift 4.1.
extension String {
func camelCased(with separator: Character) -> String {
return self.lowercased()
.split(separator: separator)
.enumerated()
.map { $0.offset > 0 ? $0.element.capitalized : $0.element.lowercased() }
.joined()
}
}
What you could do is to spilt your string based on the dash "-" (creating an array of strings) and combine its elements with the desired case:
let myString = "this-is-my-id"
let newString = myString.split(separator: "-").reduce("", { $0 + $1.capitalized })
print(newString) // "ThisIsMyId"
Your syntax works if you destructure the String.Subsequence elements by creating new strings:
str.split(separator: "-").enumerated().map { (index, element) in
return index > 0 ? String(element).capitalized : String(element)
}.joined() // better than `reduce`
Maybe the smallest implementation of conversioning from dash to camel case using reduce:
extension String {
var camelCased: String {
self.split(separator: "-")
.reduce("", { $0 + ($0.isEmpty ? String($1) : $1.capitalized) })
}
}
print("this-is-my-id".camelCased) // Prints "thisIsMyId"
A combination of all these answers will lead to the following, shortest way (I think - only 2 interations):
let str: String = "this-is-my-id"
let result = str.split(separator: "-").reduce("") {(acc, name) in
"\(acc)\(acc.count > 0 ? String(name.capitalized) : String(name))"
}
Thanks all!
You can iterate over the characters (String is a collection of characters) while holding a flag telling if the character came after a dash, in order to capitalize it:
let dashCase = "this-is-my-id"
let camelCase = dashCase.reduce(into: ("", false)) {
// mark the dash
guard $1 != "-" else { $0.1 = true; return }
$0.0 += $0.1 ? String($1).uppercased() : String($1)
// reset the flag so we don't capitalize the next ones
$0.1 = false
}.0
print(camelCase) // thisIsMyId

Swift Type 'string.index' has no subscript members

I'm currently converting C++ code to Swift and I've gotten stuck on one part. The parameter passed into the function is a string and the area where I'm stuck is when attempting to set a variable based on the second to last character of a string to check for a certain character.
The error shows up on this line:
line[i-1]
I've tried casting this value to an Int but this didn't work:
Int(line[i - 1])
I've also tried to see if the string's startIndex function which takes a Int would work but it didn't:
line.startIndex[i - 1]
Here is the full function:
func scanStringForSpecificCharacters(line: String){
var maxOpen: Int = 0;
var minOpen: Int = 0;
minOpen = 0;
maxOpen = 0;
var i = 0
while i < line.characters.count {
for character in line.characters {
//var c: Character = line[i];
if character == "(" {
maxOpen += 1;
if i == 0 || line[i - 1] != ":" {
minOpen += 1;
}
}
else if character == ")"{
minOpen = max(0,minOpen-1);
if i == 0 || line[i-1] != ":"{
maxOpen -= 1;
}
if maxOpen < 0{
break;
}
}
}
if maxOpen >= 0 && minOpen == 0{
print("YES")
}else{
print("NO")
}
}
}
Strings in Swift aren't indexed collections and instead you can access one of four different views: characters, UTF8, UTF16, or unicodescalars.
This is because Swift supports unicode, where an individual characters may actually be composed of multiple unicode scalars.
Here's a post that really helped me wrap my head around this: https://oleb.net/blog/2016/08/swift-3-strings/
Anyway, to answer you question you'll need to create an index using index(after:), index(before:), or index(_, offsetBy:).
In your case you'd want to do something like this:
line.index(line.endIndex, offsetBy: -2) // second to last character
Also, you'll probably find it easier to iterate directly using a String.Index type rather than Int:
let line = "hello"
var i = line.startIndex
while i < line.endIndex {
print(line[i])
i = line.index(after: i)
}
// prints ->
// h
// e
// l
// l
// o
Working with Strings in Swift was changed several times during it's evolution and it doesn't look like C++ at all. You cannot subscript string to obtain individual characters, you should use index class for that. I recommend you read this article:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html
As already pointed out in the other answers, the compiler error
is caused by the problem that you cannot index a Swift String with
integers.
Another problem in your code is that you have a nested loop which is
probably not intended.
Actually I would try to avoid string indexing at all and only
enumerate the characters, if possible. In your case, you can
easily keep track of the preceding character in a separate variable:
var lastChar: Character = " " // Anything except ":"
for char in line.characters {
if char == "(" {
maxOpen += 1;
if lastChar != ":" {
minOpen += 1;
}
}
// ...
lastChar = char
}
Or, since you only need to know if the preceding character is
a colon:
var lastIsColon = false
for char in string.characters {
if char == "(" {
maxOpen += 1;
if !lastIsColon {
minOpen += 1;
}
}
// ...
lastIsColon = char == ":"
}
Another possible approach is to iterate over the string and a shifted
view of the string in parallel:
for (lastChar, char) in zip([" ".characters, line.characters].joined(), line.characters) {
// ...
}
As others have already explained, trying to index into Swift strings is a pain.
As a minimal change to your code, I would recommend that you just create an array of the characters in your line up front:
let linechars = Array(line.characters)
And then anywhere you need to index into the line, use linechars:
This:
if i == 0 || line[i-1] != ":" {
becomes:
if i == 0 || linechars[i-1] != ":" {