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: "")
}
}
}
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
I have to show some text in UILabel and append read more if the text goes beyond 3 number of lines. It works fine if I set number of lines = 3 and trim the text to 120 characters or so. But if the text contains newline character then this fails.
How to handle this.
func formatText() -> String {
var formatString = self.review_description
var maxLimit = 140
if self.review_link != nil {
maxLimit = 120
}
if formatString.count > maxLimit {
let substring = formatString.dropLast(formatString.count - maxLimit)
formatString = String(substring) + "... " + AppConstants.readMoreText
}
if self.review_link != nil {
formatString = formatString + " \(AppConstants.reviewSourceText)"
}
return formatString
}
try this
make your number of lines for label as 0. because new line won't increase your char count at all
I can reverse every word in a string functionally without using a loop, but when I try to reverse EVERY OTHER WORD. I run into problems. I can do it with a loop but not functionally. What am I not seeing here?
Functionally (every word):
import UIKit
let input = "This is a sample sentence"
func reverseWords(input: String) -> String {
let parts = input.components(separatedBy: " ")
let reversed = parts.map { String($0.reversed()) }
return reversed.joined(separator: " ")
}
reverseWords(input: input)
With loop (EVERY OTHER WORD):
var sampleSentence = "This is a sample sentence"
func reverseWordsInSentence(sentence: String) -> String {
let allWords = sampleSentence.components(separatedBy:" ")
var newSentence = ""
for index in 0...allWords.count - 1 {
let word = allWords[index]
if newSentence != "" {
newSentence += " "
}
if index % 2 == 1 {
let reverseWord = String(word.reversed())
newSentence += reverseWord
} else {
newSentence += word
}
}
return newSentence
}
reverseWordsInSentence(sentence: sampleSentence)
With a slight modification of your reverseWords you can reverse every other word. Use enumerated() to combine a word with its position, and then use that to reverse odd words:
let input = "one two three four five"
func reverseOddWords(input: String) -> String {
let parts = input.components(separatedBy: " ")
let reversed = parts.enumerated().map { $0 % 2 == 0 ? String($1.reversed()) : $1 }
return reversed.joined(separator: " ")
}
print(reverseOddWords(input: input))
eno two eerht four evif
Or you could pattern your function after Swift's sort and pass the filter closure to the reverseWords function:
let input = "one two three four five"
func reverseWords(_ input: String, using filter: ((Int) -> Bool) = { _ in true }) -> String {
let parts = input.components(separatedBy: " ")
let reversed = parts.enumerated().map { filter($0) ? String($1.reversed()) : $1 }
return reversed.joined(separator: " ")
}
// default behavior is to reverse all words
print(reverseWords("one two three four five"))
eno owt eerht ruof evif
print(reverseWords("one two three four five", using: { $0 % 2 == 1 }))
one owt three ruof five
print(reverseWords("one two three four five", using: { [0, 3, 4].contains($0) }))
eno two three ruof evif
let everyThirdWord = { $0 % 3 == 0 }
print(reverseWords("one two three four five", using: everyThirdWord))
eno two three ruof five
Use stride() to generate a sequence of indexes of every other word.
Then use forEach() to select each index in the stride array and use it to mutate the word at that index to reverse it.
import UIKit
let string = "Now is the time for all good programmers to babble incoherently"
var words = string.components(separatedBy: " ")
stride(from: 0, to: words.count, by: 2)
.forEach { words[$0] = String(words[$0].reversed()) }
let newString = words.joined(separator: " ")
print(newString)
The output string is:
"woN is eht time rof all doog programmers ot babble yltnerehocni"
How can I print a binary tree in Swift so that the input 79561 prints output like this:
7
/ \
5 9
/ \
1 6
I tried to arrange this with some code using For Loops and If Statements but it didn't worked.
My code is:
import UIKit
//Variable "node" used only to arrange it in output.
var node = "0"
var space = " "
var linkLeft = "/"
var linkRight = "\\"
var str = "Hello, playground"
var height = 6
var width = height * 2 + 1
print()
//Height
for h in 1...height {
//Width
for w in 1...width {
switch h {
case 1:
if(w == width/2 + h) {
print(node, terminator: "")
} else {
print(space, terminator: "")
}
if (w == width) {
print()
}
case 2:
//print(linkLeft, terminator: "")
if(w == width/3 + h) {
print(linkLeft, terminator: "")
} else if(w == width/3 + h + 4) {
print(linkRight, terminator: "")
} else {
print(space, terminator: "")
}
if (w == width) {
print()
}
case 3:
if(w == width/5 + h) {
print(node, terminator: "")
} else if(w == width/h + h){
print(node, terminator: "")
} else {
print(space, terminator: "")
}
if (w == width) {
print()
}
break
default:
break
}
}
}
I tried to use two For Loops one for height and other one for width. But it's not working if number of nodes changes. For now I just tried to arrange places of links (/ and \), nodes and spaces, so it's not working.
Is there a possible way to do this ?
First you have to define a hierarchical tree structure (class) that allows recursive traversal of the tree nodes. How you implement it doesn't matter as long as it can provide a descriptive string and access to its left and right sub nodes.
For example (I used this for testing purposes):
class TreeNode
{
var value : Int
var left : TreeNode? = nil
var right : TreeNode? = nil
init(_ rootValue:Int)
{ value = rootValue }
#discardableResult
func addValue( _ newValue:Int) -> TreeNode
{
if newValue == value // exclude duplicate entries
{ return self }
else if newValue < value
{
if let newNode = left?.addValue(newValue)
{ return newNode }
left = TreeNode(newValue)
return left!
}
else
{
if let newNode = right?.addValue(newValue)
{ return newNode }
right = TreeNode(newValue)
return right!
}
}
}
Then you can create a recursive function to obtain the lines to print. Each line will need to be aware of lower level lines so the list of lines needs to be built from the bottom up. Recursion is an easy way to achieve this kind of interdependency.
Here's an example of a generic function that will work for any binary tree class. It expects a root node and a function (or closure) to access a node's description and left/right sub nodes :
public func treeString<T>(_ node:T, reversed:Bool=false, isTop:Bool=true, using nodeInfo:(T)->(String,T?,T?)) -> String
{
// node value string and sub nodes
let (stringValue, leftNode, rightNode) = nodeInfo(node)
let stringValueWidth = stringValue.count
// recurse to sub nodes to obtain line blocks on left and right
let leftTextBlock = leftNode == nil ? []
: treeString(leftNode!,reversed:reversed,isTop:false,using:nodeInfo)
.components(separatedBy:"\n")
let rightTextBlock = rightNode == nil ? []
: treeString(rightNode!,reversed:reversed,isTop:false,using:nodeInfo)
.components(separatedBy:"\n")
// count common and maximum number of sub node lines
let commonLines = min(leftTextBlock.count,rightTextBlock.count)
let subLevelLines = max(rightTextBlock.count,leftTextBlock.count)
// extend lines on shallower side to get same number of lines on both sides
let leftSubLines = leftTextBlock
+ Array(repeating:"", count: subLevelLines-leftTextBlock.count)
let rightSubLines = rightTextBlock
+ Array(repeating:"", count: subLevelLines-rightTextBlock.count)
// compute location of value or link bar for all left and right sub nodes
// * left node's value ends at line's width
// * right node's value starts after initial spaces
let leftLineWidths = leftSubLines.map{$0.count}
let rightLineIndents = rightSubLines.map{$0.prefix{$0==" "}.count }
// top line value locations, will be used to determine position of current node & link bars
let firstLeftWidth = leftLineWidths.first ?? 0
let firstRightIndent = rightLineIndents.first ?? 0
// width of sub node link under node value (i.e. with slashes if any)
// aims to center link bars under the value if value is wide enough
//
// ValueLine: v vv vvvvvv vvvvv
// LinkLine: / \ / \ / \ / \
//
let linkSpacing = min(stringValueWidth, 2 - stringValueWidth % 2)
let leftLinkBar = leftNode == nil ? 0 : 1
let rightLinkBar = rightNode == nil ? 0 : 1
let minLinkWidth = leftLinkBar + linkSpacing + rightLinkBar
let valueOffset = (stringValueWidth - linkSpacing) / 2
// find optimal position for right side top node
// * must allow room for link bars above and between left and right top nodes
// * must not overlap lower level nodes on any given line (allow gap of minSpacing)
// * can be offset to the left if lower subNodes of right node
// have no overlap with subNodes of left node
let minSpacing = 2
let rightNodePosition = zip(leftLineWidths,rightLineIndents[0..<commonLines])
.reduce(firstLeftWidth + minLinkWidth)
{ max($0, $1.0 + minSpacing + firstRightIndent - $1.1) }
// extend basic link bars (slashes) with underlines to reach left and right
// top nodes.
//
// vvvvv
// __/ \__
// L R
//
let linkExtraWidth = max(0, rightNodePosition - firstLeftWidth - minLinkWidth )
let rightLinkExtra = linkExtraWidth / 2
let leftLinkExtra = linkExtraWidth - rightLinkExtra
// build value line taking into account left indent and link bar extension (on left side)
let valueIndent = max(0, firstLeftWidth + leftLinkExtra + leftLinkBar - valueOffset)
let valueLine = String(repeating:" ", count:max(0,valueIndent))
+ stringValue
let slash = reversed ? "\\" : "/"
let backSlash = reversed ? "/" : "\\"
let uLine = reversed ? "¯" : "_"
// build left side of link line
let leftLink = leftNode == nil ? ""
: String(repeating: " ", count:firstLeftWidth)
+ String(repeating: uLine, count:leftLinkExtra)
+ slash
// build right side of link line (includes blank spaces under top node value)
let rightLinkOffset = linkSpacing + valueOffset * (1 - leftLinkBar)
let rightLink = rightNode == nil ? ""
: String(repeating: " ", count:rightLinkOffset)
+ backSlash
+ String(repeating: uLine, count:rightLinkExtra)
// full link line (will be empty if there are no sub nodes)
let linkLine = leftLink + rightLink
// will need to offset left side lines if right side sub nodes extend beyond left margin
// can happen if left subtree is shorter (in height) than right side subtree
let leftIndentWidth = max(0,firstRightIndent - rightNodePosition)
let leftIndent = String(repeating:" ", count:leftIndentWidth)
let indentedLeftLines = leftSubLines.map{ $0.isEmpty ? $0 : (leftIndent + $0) }
// compute distance between left and right sublines based on their value position
// can be negative if leading spaces need to be removed from right side
let mergeOffsets = indentedLeftLines
.map{$0.count}
.map{leftIndentWidth + rightNodePosition - firstRightIndent - $0 }
.enumerated()
.map{ rightSubLines[$0].isEmpty ? 0 : $1 }
// combine left and right lines using computed offsets
// * indented left sub lines
// * spaces between left and right lines
// * right sub line with extra leading blanks removed.
let mergedSubLines = zip(mergeOffsets.enumerated(),indentedLeftLines)
.map{ ( $0.0, $0.1, $1 + String(repeating:" ", count:max(0,$0.1)) ) }
.map{ $2 + String(rightSubLines[$0].dropFirst(max(0,-$1))) }
// Assemble final result combining
// * node value string
// * link line (if any)
// * merged lines from left and right sub trees (if any)
let treeLines = [leftIndent + valueLine]
+ (linkLine.isEmpty ? [] : [leftIndent + linkLine])
+ mergedSubLines
return (reversed && isTop ? treeLines.reversed(): treeLines)
.joined(separator:"\n")
}
To actually print, you'll need to supply the function with your class's node and a closure to access node descriptions and the left and right sub nodes.
extension TreeNode
{
var asString:String { return treeString(self){("\($0.value)",$0.left,$0.right)} }
}
var root = TreeNode(7)
root.addValue(9)
root.addValue(5)
root.addValue(6)
root.addValue(1)
print(root.asString)
// 7
// / \
// 5 9
// / \
// 1 6
//
root = TreeNode(80)
root.addValue(50)
root.addValue(90)
root.addValue(10)
root.addValue(60)
root.addValue(30)
root.addValue(70)
root.addValue(55)
root.addValue(5)
root.addValue(35)
root.addValue(85)
print(root.asString)
// 80
// ___/ \___
// 50 90
// __/ \__ /
// 10 60 85
// / \ / \
// 5 30 55 70
// \
// 35
//
[EDIT] Improved logic to use less space on trees with deeper right side than left. Cleaned up code and added comments to explain how it works.
//
// 12
// / \
// 10 50
// / __/ \__
// 5 30 90
// \ /
// 35 70
// / \
// 60 85
// /
// 55
//
// 12
// / \
// 10 30
// / \
// 5 90
// /
// 85
// /
// 70
// /
// 55
// /
// 48
// /
// 45
// /
// 40
// /
// 35
//
[EDIT2] made the function generic and adapted explanations.
With the generic function, the data doesn't even need to be in an actual tree structure.
For example, you could print an array containing a heap tree:
extension Array
{
func printHeapTree(reversed:Bool = false)
{
let tree = treeString( 0, reversed:reversed )
{
let left = { $0 < self.count ? $0 : nil}($0 * 2 + 1)
let right = { $0 < self.count ? $0 : nil}($0 * 2 + 2)
return ( "\(self[$0])", left, right )
}
print(tree)
}
}
let values = [7,5,9,1,6]
values.printHeapTree()
// 7
// / \
// 5 9
// / \
// 1 6
let family = [ "Me","Paul","Rosa","Vincent","Jody","John","Kate"]
family.printHeapTree()
// Me
// ___/ \___
// Paul Rosa
// / \ / \
// Vincent Jody John Kate
But for that last example, a family tree is usually presented upside down. So, I adjusted the function to allow printing a reversed tree:
family.printHeapTree(reversed:true)
// Vincent Jody John Kate
// \ / \ /
// Paul Rosa
// ¯¯¯\ /¯¯¯
// Me
[EDIT3] Added condition to exclude duplicate entries from tree in example class (TreeNode) per Emm's request
[EDIT4] changed formula for mergedSubLines so that it will compile in an actual project (was testing this in the playground).
[EDIT5] minor adjustments for Swift4, added ability to print a reversed tree, changed Array example to a heap tree.
My easy way that I found and modified a bit for swift
import UIKit
// Binary tree by class
class TreeNode
{
var value : Int
var left : TreeNode? = nil
var right : TreeNode? = nil
init(_ rootValue:Int) {
value = rootValue
}
#discardableResult
func addValue( _ newValue:Int) -> TreeNode
{
if newValue == value {
return self
}
else if newValue < value {
if let newNode = left?.addValue(newValue) {
return newNode
}
left = TreeNode(newValue)
return left!
}
else {
if let newNode = right?.addValue(newValue) {
return newNode
}
right = TreeNode(newValue)
return right!
}
}
func myPrint () {
printTree(prefix: "", n: self, isLeft: false)
}
}
func printTree(prefix: String, n: TreeNode, isLeft: Bool) {
print(prefix, (isLeft ? "|-- " : "\\-- "), n.value)
if n.left != nil {
printTree(prefix: "\(prefix) \(isLeft ? "| " : " ") ", n: n.left!, isLeft: true)
}
if n.right != nil {
printTree(prefix: "\(prefix) \(isLeft ? "| " : " ") ", n: n.right!, isLeft: false)
}
}
Input
var root = TreeNode(80)
root.addValue(50)
root.addValue(90)
root.addValue(10)
root.addValue(60)
root.addValue(30)
root.addValue(70)
root.addValue(55)
root.addValue(5)
root.addValue(35)
root.addValue(85)
root.addValue(84)
root.addValue(86)
root.addValue(92)
root.addValue(100)
root.myPrint()
Output
\-- 80
|-- 50
| |-- 10
| | |-- 5
| | \-- 30
| | \-- 35
| \-- 60
| |-- 55
| \-- 70
\-- 90
|-- 85
| |-- 84
| \-- 86
\-- 92
\-- 100