How to use variable outside the loop, after initializing inside the loop? - swift

Want to code a function that will take an array of strings named straar and an integer named k. It will return k times longest strings merged together.
code:
import UIKit
func longestConsec( strarr: [String], k: Int) -> String {
var strerr : [String] = Array()
strerr = strarr
var longest : Int
longest = 0
var longestString : String
var finalBoss : String
finalBoss = ""
for v in 1...k{
for long in strerr{
if (long.count > longest){
longest = long.count
longestString = long
}
}
finalBoss += longestString
for lang in 0...strerr.count{
if (strerr[lang] == longestString){
strerr.remove(at:lang)
}
}
}
return finalBoss
}

there are some problem with the code. The var 'longestString' needs to be initialized before being used. And in the last for loop fails because the index is mayor than the count of items. Here's the code with some corrections.
func longestConsec( strarr: [String], k: Int) -> String {
var strerr = strarr
var longest : Int
longest = 0
var longestString : String = ""
var finalBoss : String
finalBoss = ""
for _ in 1...k {
for long in strerr {
if (long.count > longest) {
longest = long.count
longestString = long
}
}
finalBoss += longestString
for lang in 1 ..< strerr.count {
if (strerr[lang] == longestString) {
strerr.remove(at:lang)
}
}
}
print("finalBoss: \(finalBoss)")
return finalBoss
}
longestConsec(strarr: ["Eleven", "Two", "Three"], k: 3)

Related

Leetcode Q. 1528. Shuffle String

Given a string s and an integer array indices of the same length.
The string s will be shuffled such that the character at the ith position moves to indices[i] in the shuffled string.
Return the shuffled string.
Input: s = "codeleet", indices = [4,5,6,7,0,2,1,3]
Output: "leetcode"
Explanation: As shown, "codeleet" becomes "leetcode" after shuffling.
class Solution {
func restoreString(_ s: String, _ indices: [Int]) -> String {
//convert the string into a hash map where all keys are Ints and the values are the Strings.
//Run a for loop through the dictionary and return the key of the value in indices.
//time complexity: O(n)
//Space complexity: O(n)
var newString = s.map{ String($0) }
var y = ""
var count = 0
var dict = [Int:String]()
var z = 0
while count < newString.count {
dict[count] = newString[count]
count += 1
}
while z < indices.count {
y.append(dict[indices[z]]!)
z += 1
}
print(dict)
return y
}
}
The first while loop creates a dictionary and the second while loop finds the values with matching keys and appends into a string. My issue is that my code is outputting two characters in the wrong location.
Input: "codeleet"
[4,5,6,7,0,2,1,3]
Output: "leetcdoe"
Can you please help me explain what I'm missing here.
Its a one to one hashing not a index based hashing which you were doing in above code below is the updated correct version of your code:-
class Solution {
func restoreString(_ s: String, _ indices: [Int]) -> String {
var newString = s.map{ String($0) }
var y = ""
var count = 0
var dict = [Int:String]()
var z = 0
while count < newString.count {
dict[indices[count]] = newString[count]
count += 1
}
while z < indices.count {
y.append(dict[z]!)
z += 1
}
print(dict)
return y
}
}
class Solution {
public String restoreString(String s, int[] indices) {
String s1="";
for(int i=0;i<s.length();i++){
for(int j=0;j<s.length();j++){
if(i==indices[j]){
s1=s1+s.charAt(j);
}
}
}return s1;
}
func restoreString(_ s: String, _ indices: [Int]) -> String {
var letters = [String]()
var result = ""
s.forEach{
letters.append(String($0))
}
for (index,value) in s.enumerated(){
letters[indices[index]] = value.description
}
result = letters.reduce("", +)
return result }

In Swift How do I iterate over an array getting 2 variables when each pair of elements is a String? and a String

I want to iterate over an array String?, String repeated pair but I cannot form the "for case let (a,b) in array" correctly.
The best I have come up with is to create a temp struct of {String?, String} and create an array of the temp structs and then iterate it but I would like to skip this step.
Below is the basic example with the last for loop showing the error Xcode reports.
class Foo {
var s1: String?
var s2: String?
var s3: String?
}
let foo = Foo()
foo.s1="Test1"
foo.s2=nil
foo.s3="Test3"
let fooArray = [foo.s1, ", ", foo.s2, "; ", foo.s3,"."]
let fooArray1 = [foo.s1,foo.s2, foo.s3]
var text:String = ""
for case let prop? in fooArray1 {
text = text + prop + " / "
}
print(text)
// The above works but now I want to use a different separator
//base on the property name
text=""
for case let (prop, sep) in fooArray { // Error <= Expression Type
// [String?] is ambiguous without more context
text = text + prop + sep
}
print(text)
Here is what I have come up with
struct temp {
var prop:String?
var sep:String
init(_ prop:String?, _ sep:String) {
self.prop=prop
self.sep=sep
}
let ary:[temp] = [ temp(foo.s1,", "), temp(foo.s2,"; "), temp(foo.s3,".") ]
text = ""
for a in ary {
if let p = a.prop {
text = text + p + a.sep
}
}
print (text)
is there another way just using the for loop
for (a,b) in fooArray {
...
}
As noted by #RJE, the inferred type of fooArray, as defined in your code, is [String?].
Here is one way to make it work:
class Foo {
var s1: String?
var s2: String?
var s3: String?
}
let foo = Foo()
foo.s1 = "Test1"
foo.s2 = nil
foo.s3 = "Test3"
let fooArray1 = [foo.s1, foo.s2, foo.s3]
let separators = [", ", "; ", "."]
var text = ""
for i in fooArray1.indices {
if let p = fooArray1[i] {
text = text + p + separators[i]
}
}
print (text) //Test1, Test3.
Or
let zipped = zip(fooArray1, separators)
let text = zipped.map { tuple -> String in
if case let (x?, y) = tuple {
return x + y
} else {
return ""
}
}.joined()
print (text) //Test1,Test3.
Or
let fooArray = [foo.s1, ", ", foo.s2, "; ", foo.s3, "."]
var text = ""
var step = 1
var index = 0
while index < fooArray.count {
if let str = fooArray[index] {
step = 1
text += str
} else {
step = 2
}
index += step
}
print(text) //Test1, Test3.
It would be better to define the initializer this way :
class Foo {
var s1: String?
var s2: String?
var s3: String?
init(s1: String?, s2: String?, s3: String?) {
self.s1 = s1
self.s2 = s2
self.s3 = s3
}
}
let foo = Foo(s1: "Test1", s2: nil, s3: "Test3")
P.S: The desired output seems to be more appropriate for a description property of the Foo class.
Thanks for the answer I was hoping through this question to get a better understanding of how to use [for] parameters. But the while solution is the solution I would probably use with the following modifications
text = ""
var index = 0
while index < fooArray.count {
if let prop = fooArray[index] {
index += 1
let sep = fooArray[index]!
index += 1
text = text + prop + sep
} else {
index += 2
}
}

Levenshtein distance in Swift3

I'm using a tutorial from Rosetta Code to calculate Levenshtein distance. It seems their code is in Swift2 so I get this error Binary operator '+' cannot be applied to operands of type '[Int]' and 'Repeated<String.CharacterView>' when doing this: var cur = [i + 2] + empty where let empty = repeatElement(s, count: 0). How can I go about this?
There were a couple of changes to make.
The construction of the Array empty.
enumerate() is now enumerated()
successor() doesn't exist anymore so I replaced it with +1
So the function is now
Swift 4:
func levDis(_ w1: String, _ w2: String) -> Int {
let empty = [Int](repeating:0, count: w2.count)
var last = [Int](0...w2.count)
for (i, char1) in w1.enumerated() {
var cur = [i + 1] + empty
for (j, char2) in w2.enumerated() {
cur[j + 1] = char1 == char2 ? last[j] : min(last[j], last[j + 1], cur[j]) + 1
}
last = cur
}
return last.last!
}
Swift 3:
func levDis(w1: String, w2: String) -> Int {
let (t, s) = (w1.characters, w2.characters)
let empty = Array<Int>(repeating:0, count: s.count)
var last = [Int](0...s.count)
for (i, tLett) in t.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in s.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : min(last[j], last[j + 1], cur[j])+1
}
last = cur
}
return last.last!
}
Updated and improved answer to Swift 4, based on #Spads answer.
extension String {
func levenshteinDistanceScore(to string: String, ignoreCase: Bool = true, trimWhiteSpacesAndNewLines: Bool = true) -> Float {
var firstString = self
var secondString = string
if ignoreCase {
firstString = firstString.lowercased()
secondString = secondString.lowercased()
}
if trimWhiteSpacesAndNewLines {
firstString = firstString.trimmingCharacters(in: .whitespacesAndNewlines)
secondString = secondString.trimmingCharacters(in: .whitespacesAndNewlines)
}
let empty = [Int](repeating:0, count: secondString.count)
var last = [Int](0...secondString.count)
for (i, tLett) in firstString.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in secondString.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : Swift.min(last[j], last[j + 1], cur[j])+1
}
last = cur
}
// maximum string length between the two
let lowestScore = max(firstString.count, secondString.count)
if let validDistance = last.last {
return 1 - (Float(validDistance) / Float(lowestScore))
}
return 0.0
}
}
infix operator =~
func =~(string: String, otherString: String) -> Bool {
return string.levenshteinDistanceScore(to: otherString) >= 0.85
}
func ~=(string: String, otherString: String) -> Bool {
return string.levenshteinDistanceScore(to: otherString) >= 0.85
}
Since #Daniel Illescas answer is not working, here is working version with Int return type and with assert.
extension String {
func levenshteinDistance(to string: String, ignoreCase: Bool = true, trimWhiteSpacesAndNewLines: Bool = true) -> Int {
var firstString = self
var secondString = string
if ignoreCase {
firstString = firstString.lowercased()
secondString = secondString.lowercased()
}
if trimWhiteSpacesAndNewLines {
firstString = firstString.trimmingCharacters(in: .whitespacesAndNewlines)
secondString = secondString.trimmingCharacters(in: .whitespacesAndNewlines)
}
let empty = [Int](repeating: 0, count: secondString.count)
var last = [Int](0...secondString.count)
for (i, tLett) in firstString.enumerated() {
var cur = [i + 1] + empty
for (j, sLett) in secondString.enumerated() {
cur[j + 1] = tLett == sLett ? last[j] : Swift.min(last[j], last[j + 1], cur[j]) + 1
}
last = cur
}
if let validDistance = last.last {
return validDistance
}
assertionFailure()
return 0
}
}

How to make a function that swaps 3 characters in a string?

For example, if I had a string RedSox and wanted to change it to SoxRed?
I'm thinking it would be something like :
func swapString (String: String) -> String {
var stringReplaced = String
var result = stringReplaced.Select(x=> x == 'A' ? 'B' : (x=='B' ? "A" : x)).ToArray()
stringReplaced = String(result)
return stringReplaced
}
this function takes the last 3 characters of a string and appends them to the beginning, there are definitely less verbose ways of doing this but it works. it will throw an error if passed a string with < 3 characters.
import UIKit
let string = "RedSox"
func changeString ( _ string : String) -> String {
var characters : Array<Character> = []
for character in string.characters {
characters.append(character)
}
var characters2 : Array<Character> = []
var position = characters.count - 3
while position < characters.count {
characters2.append(characters[position])
position += 1
}
characters.removeLast()
characters.removeLast()
characters.removeLast()
characters2.append(contentsOf: characters)
return (String(characters2))
}
var newString = changeString(string)
print (newString)
Just use the methods which the String class already provides.
It's always a good idea putting these kind of "helper" methods in an extension.
// Define String extension
extension String {
func swappedString(count swapCount: Int) -> String {
guard self.characters.count > swapCount else {
return self
}
let index = self.index(self.endIndex, offsetBy: -swapCount)
let first = self.substring(from: index)
let second = self.substring(to: index)
return first + second
}
}
// Use it
"RedSox".swappedString(count: 3) //= SoxRed

Finding the first non-repeating character in a String using Swift

This finds the duplicates in the array, but i'm looking for something that finds the first non-repeating character in a string. I've been trying to figure out a way to do this and I cannot figure it out. This is the closest i've gotten.
var strArray = ["P","Q","R","S","T","P","R","A","T","B","C","P","P","P","P","P","C","P","P","J"]
println(strArray)
var filter = Dictionary<String,Int>()
var len = strArray.count
for var index = 0; index < len ;++index {
var value = strArray[index]
if (filter[value] != nil) {
strArray.removeAtIndex(index--)
len--
}else{
filter[value] = 1
}
}
println(strArray)
In order to tell if a character repeats itself, go through the entire array once, incrementing the count of occurrences in a dictionary:
let characters = ["P","Q","R","S","T","P","R","A","T","B","C","P","P","P","P","P","C","P","P","J"]
var counts: [String: Int] = [:]
for character in characters {
counts[character] = (counts[character] ?? 0) + 1
}
let nonRepeatingCharacters = characters.filter({counts[$0] == 1})
// ["Q", "S", "A", "B", "J"]
let firstNonRepeatingCharacter = nonRepeatingCharacters.first!
// "Q"
Here is a simple solution
let inputString = "PQRSTPRATBCPPPPPCPPJ"
func nonRepeat (_ input: String) -> String {
for char in input {
if input.firstIndex(of: char) == input.lastIndex(of: char) {
return String(char)
}
}
return ""
}
print (nonRepeat(inputString))
In the above example it would print "Q"
func firstNonRepeatedCharacter(input: String) -> Character?{
var characterCount : [Character : Int] = [:]
var uniqueCharacter: Character?
for character in input{
if let count = characterCount[character]{
characterCount[character] = count + 1
if(uniqueCharacter == character)
{
uniqueCharacter = nil
}
}
else{
characterCount[character] = 1
if(uniqueCharacter == nil){
uniqueCharacter = character
}
}
}
return uniqueCharacter
}
Without extra loop to find character from characterCount dictionary
Here is the way I have found to detect the first non-repeated character. It removes spaces and punctuation to find the actual letter or number that does not repeat.
extension String {
func removeNonAlphaNumChars() -> String {
let charSet = NSCharacterSet.alphanumericCharacterSet().invertedSet
return self
.componentsSeparatedByCharactersInSet(charSet)
.joinWithSeparator("")
}
var firstNonRepeatedCharacter: Character? {
let alphaNumString = self.removeNonAlphaNumChars()
let characters = alphaNumString.characters
let count = characters.count
guard count > 0 else { return nil }
// Find unique chars
var dict: [Character: Int?] = [:]
for (index, char) in characters.enumerate() {
if dict[char] != nil {
dict[char] = (nil as Int?)
}
else {
dict[char] = index
}
}
return dict.filter { $0.1 != nil }.sort { $0.1 < $1.1 }.first?.0
}
}
I totally wonder why the accepted answer was considered correct. They are using
.first
method of a dictionary and that according to documentation would return a random element in the dictionary and not the first element as a dictionary in swift is not ordered like an array.
please do find below an implementation that works
func firstNonRepeatingLetter(_ str: String) -> String{
var characterDict = [String : Int]()
for character in str{
let lower = character.lowercased()
if let count = characterDict[lower]{
characterDict[lower] = count + 1
}else{
characterDict[lower] = 1
}
}
let filtered = characterDict.filter { $0.value == 1}
for character in str{
let lower = character.lowercased()
if let _ = filtered[lower]{
return lower
}
}
return ""
}
firstNonRepeatingLetter("moonmen") would return "e".
We can iterate once and keep the letter counts inside a dictionary.
Then, iterate again and return first letter where we see it was encountered once only (or "_" if not found a non-repeating letter):
func firstNotRepeatingCharacter(s: String) -> Character {
var letterCounts: [String: Int] = [:]
var result: Character = "_"
for letter in s {
if let currentLetterCount = letterCounts[String(letter)] {
letterCounts[String(letter)] = currentLetterCount + 1
} else {
letterCounts[String(letter)] = 1
}
}
for letter in s {
if letterCounts[String(letter)] == 1 {
result = letter
break
}
}
return result
}
OrderedDictionary makes this easy for all Sequences of Hashables, not just Strings:
import struct OrderedCollections.OrderedDictionary
extension Sequence where Element: Hashable {
var firstUniqueElement: Element? {
OrderedDictionary(zip(self, true)) { _, _ in false }
.first(where: \.value)?
.key
}
}
/// `zip` a sequence with a single value, instead of another sequence.
public func zip<Sequence: Swift.Sequence, Constant>(
_ sequence: Sequence, _ constant: Constant
) -> LazyMapSequence<
LazySequence<Sequence>.Elements,
(LazySequence<Sequence>.Element, Constant)
> {
sequence.lazy.map { ($0, constant) }
}
func getFirstUniqueChar(string:String)->Character?{
var counts: [String: Int] = [:]
for character in string {
let charString = "\(character)"
counts[charString] = (counts[charString] ?? 0) + 1
}
let firstNonRepeatingCharacter = string.first {counts["\($0)"] == 1}
return firstNonRepeatingCharacter
}
print(getFirstUniqueChar(string: string))
import Foundation
import Glibc
var str:String = "aacbbcee"//your input string
var temp:String = ""
var dict:[Character:Int] = [:]
for char in str{
if let count = dict[char]{
dict[char] = count+1//storing values in dict and incrmenting counts o key
}
else{
dict[char] = 0
}
}
var arr:[Character] = []
for (key, value) in dict{
if value == 0{
arr.append(key)//filtering out, take characters which has value>0
} //int(arr)
}//print(arr.count)
if arr.count != 0{
outer:for char in str{//outer is labeling the loop
for i in arr{
if i == char{
print(i,"is first")//matching char with array elements if found break
break outer
}
else{
continue
}
}
}
}
else{
print("not found")
}
func firstNonRepeatedChar(string: String) -> Character {
var arr: [Character] = []
var dict: [Character : Int] = [:]
for character in string.description {
arr.append(character)
}
for character in arr {
dict[character] = (dict[character] ?? 0) + 1
}
let nonRepeatedArray = arr.filter { char in
if dict[char] == 1 {return true}
return false
}
let firstNonRepeatedChar = nonRepeatedArray.first
return firstNonRepeatedChar!
}
print(firstNonRepeatedChar(string: "strinstrig"))