I am trying to find the first repeating character in swift, and returning the character found. I am getting a bunch of errors with this code, I am not sure why this is not working.
var myArry = "Hello, World"
var counts = [Character]()
func findRepeating(myArry: String) -> Character
{
counts = []
for char in myArry.characters
{
if char in counts
{
print("Character found")
return char
}
else
{
counts.append(char)
}
}
return "A"
}
Most simple answer:
let str = "abcdefghijkhlmnop"
var count = 0
for char in str.characters {
for charNext in str.characters {
if (char == charNext) {
count += 1
if (count > 1) {
return char // h
}
}
}
count = 0
}
Related
I have the following string
let a:String = "r0bqkb0r/pppppppp/00n00n00/00000000/000P0000/0000B000/PPP0PPPP/RN0QKBNR/"
and want to convert this to PGN notation so the final result should be
result = "r1bqkb1r/pppppppp/2n2n2/8/3P4/4B3/PPP1PPPP/RN1QKBNR/"
The PGN notation converts the zeros to counts found. Normally in python, I would just use
import chess.pgn
Before deep diving into python library, is there is a succinct and 'Swift' way to do this?
Here is a solution using reduce and a separate counter
Update, rewrote it as an extension to String
extension String {
func pgpNotation() -> String {
var zeroCounter = 0
var result = self.reduce(into: "") {
if $1 == "0" {
zeroCounter += 1
return
}
if zeroCounter > 0 {
$0.append("\(zeroCounter)")
zeroCounter = 0
}
$0.append($1)
}
if zeroCounter > 0 { result.append("\(zeroCounter)")}
return result
}
}
Examples
let x = "r00d00"
print(x.pgpNotation())
let a:String = "r0bqkb0r/pppppppp/00n00n00/00000000/000P0000/0000B000/PPP0PPPP/RN0QKBNR/"
print(a.pgpNotation())
r2d2
r1bqkb1r/pppppppp/2n2n2/8/3P4/4B3/PPP1PPPP/RN1QKBNR/
There is no direct function for that but I just created a program for fun. You can check this out:-
let str = "r0bqkb0r/pppppppp/00n00n00/00000000/000P0000/0000B000/PPP0PPPP/RN0QKBNR/"
var newStr = ""
var flag = 0
// Do any additional setup after loading the view.
for char in str {
if flag == 0 {
if char == "0" {
flag += 1
}
else {
newStr.append(char)
}
}
else {
if char == "0" {
flag += 1
}
else {
newStr.append("\(flag)")
flag = 0
if char == "0" {
flag += 1
}
else {
newStr.append(char)
}
}
}
}
print(newStr)
There doesn't exist any direct method to get the pgn notation String. You can use a forEach(_:) instead, i.e.
let a = "r0bqkb0r/pppppppp/00n00n00/00000000/000P0000/0000B000/PPP0PPPP/RN0QKBNR/"
var result = ""
var count = 0
a.forEach {
if $0 == "0" {
count += 1
} else {
if count != 0 {
result.append("\(count)")
count = 0
}
result.append($0)
}
}
print(result) //r1bqkb1r/pppppppp/2n2n2/8/3P4/4B3/PPP1PPPP/RN1QKBNR/
With a simple regex and a loop (just to propose an original solution):
let a = "r0bqkb0r/pppppppp/00n00n00/00000000/000P0000/0000B000/PPP0PPPP/RN0QKBNR/"
extension String {
var chessPGN : String {
var result = self
let regex = try! NSRegularExpression(pattern: "0+")
while let match = regex.matches(in: result, range: .init(location: 0, length: result.count)).first {
if let stringRange = Range(match.range , in: result) {
result.replaceSubrange(stringRange, with: match.range.length.description)
}
}
return result
}
}
print(a.chessPGN) // r1bqkb1r/pppppppp/2n2n2/8/3P4/4B3/PPP1PPPP/RN1QKBNR/
EDIT: A version calling only once the regex
extension String {
var chessPGN : String {
var result = self
let regex = try! NSRegularExpression(pattern: "0+")
for match in regex.matches(in: result, range: .init(location: 0, length: result.count)).sorted(by: { $0.range.location > $1.range.location }) {
if let stringRange = Range(match.range , in: result) {
result.replaceSubrange(stringRange, with: match.range.length.description)
}
}
return result
}
}
Convert String in this way
let initialString = "atttbcdddd"
// result must be like this "at3bcd4"
But repetition must be more than 2. For example, if we have "aa" the result will be "aa", but if we have "aaa", the result will be "a3"
One more example:
let str = "aahhhgggg"
//result "aah3g4"
My try:
func encrypt(_ str: String) -> String {
let char = str.components(separatedBy: "t") //must input the character
var count = char.count - 1
var string = ""
string.append("t\(count)")
return string
}
if i input "ttttt" it will return "t5" but i should input the character
What you are looking for is the “Run-length encoding”. Note that this is not an encryption!
Here is a possible implementation (explanations inline):
func runLengthEncode(_ str: String) -> String {
var result = ""
var pos = str.startIndex // Start index of current run
while pos != str.endIndex {
let char = str[pos]
// Find index of next run (or `endIndex` if there is none):
let next = str[pos...].firstIndex(where: { $0 != char }) ?? str.endIndex
// Compute the length of the current run:
let length = str.distance(from: pos, to: next)
// Append compressed output to the result:
result.append(length <= 2 ? String(repeating: char, count: length) : "\(char)\(length)")
pos = next // ... and continue with next run
}
return result
}
Examples:
print(runLengthEncode("atttbcdddd")) // at3bcd4
print(runLengthEncode("aahhhgggg")) // aah3g4
print(runLengthEncode("abbbaaa")) // ab3a3
Checkout this :
func convertString(_ input : String) -> String {
let allElements = Array(input)
let uniqueElements = Array(NSOrderedSet(array: allElements)) as! [Character]
var outputString = ""
for uniqueChar in uniqueElements {
var count = 0
for char in allElements {
if char == uniqueChar {
count+=1
}
}
if count > 2 {
outputString += "\(uniqueChar)\(count)"
} else if count == 2 {
outputString += "\(uniqueChar)\(uniqueChar)"
} else {
outputString += "\(uniqueChar)"
}
}
return outputString
}
Input : convertString("atttbcdddd")
Output : at3bcd4
I've tried it before for one of the interview and also I think you too :). However, very simple way to do it is just go through step by step of code.
let initialString = "atttbcdddd"
var previousChar: Character = " "
var output = ""
var i = 1 // Used to count the repeated charaters
var counter = 0 // To check the last character has been reached
//Going through each character
for char in initialString {
//Increase the characters counter to check the last element has been reached. If it is, add the character to output.
counter += 1
if previousChar == char { i += 1 }
else {
output = output + (i == 1 ? "\(previousChar)" : "\(previousChar)\(i)")
i = 1
}
if initialString.count == counter {
output = output + (i == 1 ? "\(previousChar)" : "\(previousChar)\(i)")
}
previousChar = char
}
let finalOutput = output.trimmingCharacters(in: .whitespacesAndNewlines)
print(finalOutput)
let initialString = "atttbcdddd"
let myInitialString = initialString + " "
var currentLetter: Character = " "
var currentCount = 1
var answer = ""
for (_, char) in myInitialString.enumerated(){
if char == currentLetter {
currentCount += 1
} else {
if currentCount > 1 {
answer += String(currentCount)
}
answer += String(char)
currentCount = 1
currentLetter = char
}
}
print(answer)
Use reduce here.
func exp(_ s : String, _ term: String) -> String{ //term_inator: Any Char not in the Sequence.
guard let first = s.first else {return ""}
return """
\(s.dropFirst().appending(term).reduce(("\(first)",1)){ r, c in
let t = c == r.0.last!
let tc = t ? r.1 : 0
let tb = t ? "" : "\(c)"
let ta = t ? "" : r.1 > 2 ? "\(r.1)" : r.1 == 2 ? "\(r.0.last!)" : ""
return (r.0 + ta + tb, tc + 1)
}.0.dropLast())
"""}
print(exp(initialString, " "))
let initialString = "abbbaaa" // ab3a3
let initialString = "aahhhgggg" // aah3g4
let initialString = "aabbaa" // aabbaa
I would like to be able to find and replace occurrences of a substring in a native Swift string without bridging to the NS class. How can I accomplish this?
This is not a duplicate of this question, as that question is about replacing a single character. This question is about finding and replacing a substring, which may contain many characters.
Method without Foundation:
extension String {
func replacing(_ oldString: String, with newString: String) -> String {
guard !oldString.isEmpty, !newString.isEmpty else { return self }
let charArray = Array(self.characters)
let oldCharArray = Array(oldString.characters)
let newCharArray = Array(newString.characters)
var matchedChars = 0
var resultCharArray = [Character]()
for char in charArray {
if char == oldCharArray[matchedChars] {
matchedChars += 1
if matchedChars == oldCharArray.count {
resultCharArray.append(contentsOf: newCharArray)
matchedChars = 0
}
} else {
for i in 0 ..< matchedChars {
resultCharArray.append(oldCharArray[i])
}
if char == oldCharArray[0] {
matchedChars = 1
} else {
matchedChars = 0
resultCharArray.append(char)
}
}
}
return String(resultCharArray)
}
}
Example usage:
let myString = "Hello World HelHelloello Hello HellHellooo"
print(myString.replacing("Hello", with: "Hi"))
Output:
Hi World HelHiello Hi HellHioo
Method using Foundation:
You can use the replacingOccurrences method on the String struct.
let myString = "Hello World"
let newString = myString.replacingOccurrences(of: "World", with: "Everyone")
print(newString) // prints "Hello Everyone"
generic and pure Swift approach
func splitBy<T: RangeReplaceableCollection>(_ s:T, by:T)->[T] where T.Iterator.Element:Equatable {
var tmp = T()
var res = [T]()
var i:T.IndexDistance = 0
let count = by.count
var pc:T.Iterator.Element {
get {
i %= count
let idx = by.index(by.startIndex, offsetBy: i)
return by[idx]
}
}
for sc in s {
if sc != pc {
i = 0
if sc != pc {
} else {
i = i.advanced(by: 1)
}
} else {
i = i.advanced(by: 1)
}
tmp.append(sc)
if i == count {
tmp.removeSubrange(tmp.index(tmp.endIndex, offsetBy: -i)..<tmp.endIndex)
res.append(tmp)
tmp.removeAll()
}
}
res.append(tmp)
return res
}
func split(_ s:String, by:String)->[String] {
return splitBy(s.characters, by: by.characters).map(String.init)
}
extension RangeReplaceableCollection where Self.Iterator.Element: Equatable {
func split(by : Self)->[Self] {
return splitBy(self, by: by)
}
}
how to use it?
let str = "simple text where i would like to replace something with anything"
let pat = "something"
let rep = "anything"
let s0 = str.characters.split(by: pat.characters).map(String.init)
let res = s0.joined(separator: rep)
print(res) // simple text where i would like to replace anything with anything
let res2 = split(str, by: pat).joined(separator: rep)
print(res2) // simple text where i would like to replace anything with anything
let arr = [1,2,3,4,1,2,3,4,1,2,3]
let p = [4,1]
print(arr.split(by: p)) // [[1, 2, 3], [2, 3], [2, 3]]
I am trying to write a program to find the practical numbers, from an input from 1 to n.
Practical numbers : https://en.wikipedia.org/wiki/Practical_number
My code is running correctly but it is extremely slow - takes over 20 minutes when it should take 10 seconds. This happens when calculating numbers around 50 - it gets stuck at 44.
It is written in Swift
import Foundation
func getInteger() -> Int {
var firstNum:Int = 0
while true {
// get value from user. Using optional input since readLine returns an optional string.
let input = readLine()
// ensure string is not nil
if let unwrappedInput = input {
if let unwrappedInt = Int(unwrappedInput) {
firstNum = unwrappedInt
break
}
else { // the input doesn't convert into an int
print("`\(unwrappedInput)` is not an integer. Please enter an integer")
}
}
else { // did not enter anything
print("Please enter an integer")
}
}
return firstNum
}
func addOne(signArray: [Int]) -> [Int] { // finds the combinations
var signArray2 = [Int]()
for i in 0...signArray.count-1 {
signArray2.append (signArray[i])
}
for i in 0...signArray2.count-1 {
if signArray2[i] == 1 {
signArray2[i] = 0
}
else {
signArray2[i] = 1
break
}
}
return signArray2
}
func signEval (signArray: [Int], divArray: [Int], inNum: Int) -> Bool {// changes 2nd
var counts = 0
for i in 0...divArray.count-1 {
if signArray[i] == 0 {
counts = divArray[i] + counts }
if counts == inNum {
return true
}
}
return false
}
print("Please enter a number to find the summable numbers up to that number:")
var input2 = getInteger()// if num = 1 print 1 if num = 2 print 1 and 2 else print >2 1, 2
var inNum = 0
var numHalf = 0.0
var numRound = 0.0
var numCheck = false
var numCheck2 = false
var numQuarter = 0.0
var numSixth = 0.0
var divArray:[Int] = []
var theirArray = [Int]()
var signArray = [Int]()// array of 0s and 1s
var summableArray:[Int] = [1,2] // need to check if num is bigger than 2!
for input in 1...input2 {
numHalf = Double (input) / 2.0
numRound = round(numHalf)
if numRound == numHalf {
numCheck = true }
if input > 2 && numCheck == false { // odd numbers greater than one are not summable
}
else { // these are possible summable nums
numQuarter = Double (input) / 4.0
numRound = round(numQuarter)
if numRound == numQuarter {
numCheck = true
}
else {
numCheck = false
}
numSixth = Double(input) / 6.0
numRound = round(numSixth)
if numRound == numSixth {
numCheck2 = true }
else { numCheck2 = false}
if numCheck == true || numCheck2 == true {
theirArray = []
divArray = []
signArray = []
summableArray = []
for i in 1...input {
theirArray.append (i)
}
for i in 1...input { // creates an array of all the diviors of inputted number
if input%i == 0 {
divArray.append (i)
}
}
for j in 1...divArray.count {//
signArray.append(0)
}
for i in 1...input{
let x: Int = Int(pow(Double(2),Double(input-1)))// int 2 to the power of input -1
var Boolcheck = false
for q in 1...x-1 { // i to 2^n -1 (sequence to check)
Boolcheck = (signEval(signArray: signArray, divArray: divArray, inNum: i))// checks
signArray = addOne(signArray: signArray)// adding the ones to the array
if Boolcheck == true {
summableArray.append(i)// creates array of mini summable numbers
break
}
}
if summableArray.count == input {
print ("\(input)")
}
}
}
}
}
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"))