How to split a string at the last occurence of a sequence - swift

Target: A string with a built-in separator shall be split in an int and another string. In the case that the separator sequence '###' occurs more than once, the string shall always be spliced at the last '###'.
Is there an operator like string.lastIndexOf("###"), like in C#?
This is how my parser looks like:
func parseTuple(from string: String) -> (String, Int)? {
let parsedString = string.components(separatedBy: "###")
if let tupleString = String(parsedString[0]), let tupleInt = Int(parsedString[1]) {
return (tupleString, tupleInt)
} else {
return nil
}
}

The range(of:...) method of String has a .backwards option
to find the last occurrence of a string.
Then substring(to:) and substring(from:) can be used with the
lower/upper bound of that range to extract the parts of the string
preceding/following the separator:
func parseTuple(from string: String) -> (String, Int)? {
if let theRange = string.range(of: "###", options: .backwards),
let i = Int(string.substring(from: theRange.upperBound)) {
return (string.substring(to: theRange.lowerBound), i)
} else {
return nil
}
}
Example:
if let tuple = parseTuple(from: "Connect###Four###Player###7") {
print(tuple)
// ("Connect###Four###Player", 7)
}
Swift 4 update:
func parseTuple(from string: String) -> (String, Int)? {
if let theRange = string.range(of: "###", options: .backwards),
let i = Int(string[theRange.upperBound...]) {
return (String(string[...theRange.lowerBound]), i)
} else {
return nil
}
}

let input = "Connect###Four###Player###7"
let seperator = "###"
// split components
var components = input.components(separatedBy: seperator)
// remove the last component ...
components = Array(components.dropLast())
// ... and re-join the remaining ones
let output = components.joined(separator: seperator)
print(output)
prints:
Connect###Four###Player

Related

How to cut last characters of string and save it as variable in swift?

I have a string of test#me
now I want to create a code that let me cut where the # is and save it as a variable, so the expected result is string1 = test string2 = #me
a code will be something like this
func test(string: String) {
var mString = string
var cuttedString = mString.cutFrom("#")
print(mString)
print(cuttedString)
}
test(string: "test#me")
result:
test
#me
Here is an extension of String which performs the function you desire. It takes a String and mutates the calling String by removing everything from that part on, and it returns the part that was removed.
import Foundation
extension String {
mutating func cut(from string: String) -> String {
if let range = self.range(of: string) {
let cutPart = String(self[range.lowerBound...])
self.removeSubrange(range.lowerBound...)
return cutPart
}
else {
return ""
}
}
}
func test(string: String) {
var mString = string
let cutString = mString.cut(from: "#")
print(mString)
print(cutString)
}
test(string: "test#me")
test
#me
A Generic Implementation
Here is a generic implementation suggested by #LeoDabus in the comments:
extension StringProtocol where Self: RangeReplaceableCollection {
#discardableResult mutating func removeSubrange<S: StringProtocol>(from string: S) -> SubSequence {
guard let range = range(of: string) else { return "" }
defer { removeSubrange(range.lowerBound...) }
return self[range.lowerBound...]
}
}
It nicely demonstrates:
Extending a protocol instead of String to allow the function to be used with other types such as String.Subsequence.
The use of #discardableResult which allows the function to be called to shorten the String without using the substring that is returned.
Using a guard let statement to unwrap the optional return from range(of:) and provide an early exit if the range is nil.
The use of defer to delay the removal of the substring until after the substring has been returned which avoids the use a local variable.
Use suffix(from:) in combination with firstIndex(of:)
let string = "test#me"
let last = string.suffix(from: string.firstIndex(of: "#") ?? string.startIndex)
Note that this returns the full string if "#" is not found, you could instead return an empty string by replacing string.startIndex with string.endIndex
To split the string in two parts, ie "test" and "#me"
var first: String = ""
var last: String = ""
if let index = string.firstIndex(of: "#") {
last = String(string.suffix(from: index))
first = String(string.prefix(upTo: index))
}
print(first, last)
You can use String subscript for this:
func test(string: String) {
guard let atIndex = string.firstIndex(of: "#") else { return }
let mString = string[string.startIndex...string.index(before: atIndex)]
let cuttedString = string[atIndex..<string.endIndex]
print(mString)
print(cuttedString)
}
func test(string: String) {
let mString = string.prefix { $0 != "#" }
let cuttedString = string.suffix(from: string.firstIndex(of: "#") ?? string.startIndex)
print(mString)
print(cuttedString)
}
test(string: "test#me")
// prints test
// #me
But remember that mString and cuttedString are not String but Substring, so take care of correct usage.
There are various ways to do this.
You could use components(separatedBy:) to break the string into pieces, and then add an # back to the last one:
extension String {
func cutFrom(_ divider: Character) -> String {
let array = components(separatedBy: String(divider))
//For an Optional, `map()` returns nil if the optional is empty,
//Or the result of applying the closure to the unwrapped contents if not
return array.last.map {String(divider) + $0} ?? ""
}
}
Alternately, you could use firstIndex to find the index of the first divider character in the string, and then return a substring from that index to the end:
extension String {
func cutFrom(_ divider: Character) -> String {
//For an Optional, `map()` returns nil if the optional is empty,
//Or the result of applying the closure to the unwrapped contents if not
return firstIndex(of: divider).map { String(self[$0..<endIndex])} ?? ""
}
}
It might be cleaner to have both versions of the function return Optionals, and return NIL if the divider character can't be found. You also might want to adjust the logic to deal with strings where the divider character occurs more than once.

Swift extract string between strings using regex

I found this code online
let sample = "#This is an [hello] amazing [world]"
let regex = try? NSRegularExpression(pattern: "#(.*?)\\[.+?\\]", options: [])
let matches = regex!.matches(in: sample, options: [], range: NSMakeRange(0, sample.count))
for match in matches {
let r = (sample as NSString).substring(with: match.range)
print(r)
}
Current output
#This is an [hello]
expected output
hello
How can I extract only the needed text?
NOTE
In my case there could be multiple square brackets. See "[anotherWorld] #This is an [hello] amazing [world]". I need the text between the square brackets which is immediately next to #somerandomtext. In given sample I need hello only
You have to use a capture group to get the text between specific characters.
The pattern
"#[^\[]+\[([^\]]+)\]"
searches for a # then for one or more characters which are not [ ([^\[]+)then a [ (\[) then it captures () one or more characters which are not ] ([^\]]+) and finally it searches for a ] (\]).
let sample = "#This is an [hello] amazing [world]"
let regex = try! NSRegularExpression(pattern: #"#[^\[]+\[([^\]]+)\]"#)
if let match = regex.firstMatch(in: sample, range: NSRange(sample.startIndex..., in: sample)) {
let range = Range(match.range(at: 1), in: sample)!
let result = String(sample[range])
print(result)
}
Your way to create an NSRange and the bridge to NSString are bad practices. There are dedicated APIs to handle NSRange
If there should not be a # or [ or ] after matching the # and the wanted match from [...], you could make the pattern a bit more restrictive extending the negated character class and use a capturing group:
#[^#\]\[]+\[([^\]\[]+)\]
In parts
# Match a # char
[^#\]\[]+ Negated character class, match 1+ times any char except # [ ]
\[ Match [
( Capture group 1
[^\]\[]+ match 1+ times any char except [ ]
) Close group
\] Match ]
Regex demo
The regex approach it is already answered so I will post a native Swift approach:
let string = "[anotherWorld] #This is an [hello] amazing [world]"
if let hashTag = string.firstIndex(of: "#"),
let openBracket = string[hashTag...].firstIndex(of: "["),
let closedBracket = string[openBracket...].firstIndex(of: "]") {
let substring = string[string.index(after: openBracket)..<closedBracket]
let result = String(substring)
print(result) // "hello\n"
}
String manipulation in Swift is not very Swifty but you can extend Collection and create some SubSequence methods to make your life easier:
extension Collection where Element: Equatable {
func firstIndex(after element: Element) -> Index? {
guard let index = firstIndex(of: element) else { return nil }
return self.index(after: index)
}
func subSequence(from element: Element) -> SubSequence? {
guard let index = firstIndex(of: element) else { return nil }
return self[index...]
}
func subSequence(after element: Element) -> SubSequence? {
guard let index = firstIndex(after: element) else { return nil }
return self[index...]
}
func subSequence(upTo element: Element) -> SubSequence? {
guard let index = firstIndex(after: element) else { return nil }
return self[..<index]
}
func subSequence(upThrough element: Element) -> SubSequence? {
guard let index = firstIndex(of: element) else { return nil }
return self[...index]
}
func subSequence(from element: Element, upTo: Element) -> SubSequence? {
guard
let lower = firstIndex(of: element),
let upper = self[lower...].firstIndex(of: upTo)
else { return nil }
return self[lower..<upper]
}
func subSequence(from element: Element, upThrough: Element) -> SubSequence? {
guard
let lower = firstIndex(of: element),
let upper = self[lower...].firstIndex(of: upThrough)
else { return nil }
return self[lower...upper]
}
func subSequence(after element: Element, upTo: Element) -> SubSequence? {
guard
let lower = firstIndex(after: element),
let upper = self[lower...].firstIndex(of: upTo)
else { return nil }
return self[lower..<upper]
}
func subSequence(after element: Element, upThrough: Element) -> SubSequence? {
guard
let lower = firstIndex(after: element),
let upper = self[lower...].firstIndex(of: upThrough)
else { return nil }
return self[lower...upper]
}
}
Now you can get any subsequence between two elements (in the String case a Substring between two characters):
let string = "[anotherWorld] #This is an [hello] amazing [world]"
let subString = string.subSequence(after: "#")?.subSequence(after: "[", upTo: "]") // "hello"

Split string by components and keep components in place

Unlike string.components(separatedBy: ...) I want to keep the separators in place in the resulting array. Code is more explanatory
let input = "foo&bar|hello"
let output = string.tokenize(splitMarks: ["&", "|"])
let desiredResult = ["foo", "&", "bar", "|", "hello"]
Is there any function in the standard library which does this? If not how can I implement such a function?
For that you need to loop through the String and check its each characters that is it tokens or not. You can make extension of String for that like this.
extension String {
func stringTokens(splitMarks: Set<String>) -> [String] {
var string = ""
var desiredOutput = [String]()
for ch in self.characters {
if splitMarks.contains(String(ch)) {
if !string.isEmpty {
desiredOutput.append(string)
}
desiredOutput.append(String(ch))
string = ""
}
else {
string += String(ch)
}
}
if !string.isEmpty {
desiredOutput.append(string)
}
return desiredOutput
}
}
Now you can call this function like this way.
let input = "foo&bar|hello"
print(input.stringTokens(splitMarks: ["&", "|"]))
Output
["foo", "&", "bar", "|", "hello"]
You can use rangeOfCharacter(from: CharacterSet, ...) in a loop to
find the next occurrence of a split mark in the string, and then
append both the preceding part and the separator to an array:
extension String {
func tokenize(splitMarks: String) -> [Substring] {
let cs = CharacterSet(charactersIn: splitMarks)
var result = [Substring]()
var pos = startIndex
while let range = rangeOfCharacter(from: cs, range: pos..<endIndex) {
// Append string preceding the split mark:
if range.lowerBound != pos {
result.append(self[pos..<range.lowerBound])
}
// Append split mark:
result.append(self[range])
// Update position for next search:
pos = range.upperBound
}
// Append string following the last split mark:
if pos != endIndex {
result.append(self[pos..<endIndex])
}
return result
}
}
Example:
let input = "foo&bar|hello"
let output = input.tokenize(splitMarks: "&|")
print(output)
// ["foo", "&", "bar", "|", "hello"]

Find the Range of the Nth word in a String

What I want is something like
"word1 word2 word3".rangeOfWord(2) => 6 to 10
The result could come as a Range or a tuple or whatever.
I'd rather not do the brute force of iterating over the characters and using a state machine. Why reinvent the lexer? Is there a better way?
In your example, your words are unique, and you can use the following method:
let myString = "word1 word2 word3"
let wordNum = 2
let myRange = myString.rangeOfString(myString.componentsSeparatedByString(" ")[wordNum-1])
// 6..<11
As pointed out by Andrew Duncan in the comments below, the above is only valid if your words are unique. If you have non-unique words, you can use this somewhat less neater method:
let myString = "word1 word2 word3 word2 word1 word3 word1"
let wordNum = 7 // 2nd instance (out of 3) of "word1"
let arr = myString.componentsSeparatedByString(" ")
var fromIndex = arr[0..<wordNum-1].map { $0.characters.count }.reduce(0, combine: +) + wordNum - 1
let myRange = Range<String.Index>(start: myString.startIndex.advancedBy(fromIndex), end: myString.startIndex.advancedBy(fromIndex+arr[wordNum-1].characters.count))
let myWord = myString.substringWithRange(myRange)
// string "word1" (from range 36..<41)
Finally, lets use the latter to construct an extension of String as you have wished for in your question example:
extension String {
private func rangeOfNthWord(wordNum: Int, wordSeparator: String) -> Range<String.Index>? {
let arr = myString.componentsSeparatedByString(wordSeparator)
if arr.count < wordNum {
return nil
}
else {
let fromIndex = arr[0..<wordNum-1].map { $0.characters.count }.reduce(0, combine: +) + (wordNum - 1)*wordSeparator.characters.count
return Range<String.Index>(start: myString.startIndex.advancedBy(fromIndex), end: myString.startIndex.advancedBy(fromIndex+arr[wordNum-1].characters.count))
}
}
}
let myString = "word1 word2 word3 word2 word1 word3 word1"
let wordNum = 7 // 2nd instance (out of 3) of "word1"
if let myRange = myString.rangeOfNthWord(wordNum, wordSeparator: " ") {
// myRange: 36..<41
print(myString.substringWithRange(myRange)) // prints "word1"
}
You can tweak the .rangeOfNthWord(...) method if word separation is not unique (say some words are separated by two blankspaces " ").
Also pointed out in the comments below, the use of .rangeOfString(...) is not, per se, pure Swift. It is, however, by no means bad practice. From Swift Language Guide - Strings and Characters:
Swift’s String type is bridged with Foundation’s NSString class. If
you are working with the Foundation framework in Cocoa, the entire
NSString API is available to call on any String value you create when
type cast to NSString, as described in AnyObject. You can also use a
String value with any API that requires an NSString instance.
See also the NSString class reference for rangeOfString method:
// Swift Declaration:
func rangeOfString(_ searchString: String) -> NSRange
I went ahead and wrote the state machine. (Grumble..) FWIW, here it is:
extension String {
private func halfOpenIntervalOfBlock(n:Int, separator sep:Character? = nil) -> (Int, Int)? {
enum State {
case InSeparator
case InPrecedingSeparator
case InWord
case InTarget
case Done
}
guard n > 0 else {
return nil
}
var state:State
if n == 1 {
state = .InPrecedingSeparator
} else {
state = .InSeparator
}
var separatorNum = 0
var startIndex:Int = 0
var endIndex:Int = 0
for (i, c) in self.characters.enumerate() {
let inSeparator:Bool
// A bit inefficient to keep doing this test.
if let s = sep {
inSeparator = c == s
} else {
inSeparator = c == " " || c == "\n"
}
endIndex = i
switch state {
case .InPrecedingSeparator:
if !inSeparator {
state = .InTarget
startIndex = i
}
case .InTarget:
if inSeparator {
state = .Done
}
case .InWord:
if inSeparator {
separatorNum += 1
if separatorNum == n - 1 {
state = .InPrecedingSeparator
} else {
state = .InSeparator
}
}
case .InSeparator:
if !inSeparator {
state = .InWord
}
case .Done:
break
}
if state == .Done {
break
}
}
if state == .Done {
return (startIndex, endIndex)
} else if state == .InTarget {
return (startIndex, endIndex + 1) // We ran off end.
} else {
return nil
}
}
func rangeOfWord(n:Int) -> Range<Index>? {
guard let (s, e) = self.halfOpenIntervalOfBlock(n) else {
return nil
}
let ss = self.startIndex.advancedBy(s)
let ee = self.startIndex.advancedBy(e)
return Range(start:ss, end:ee)
}
}
It's not really clear whether the string has to be considered divided in words by separators it may contains, or if you're just looking for a specific substring occurrence.
Anyway both cases could be addressed in this way in my opinion:
extension String {
func enumerateOccurencies(of pattern: String, _ body: (Range<String.Index>, inout Bool) throws -> Void) rethrows {
guard
!pattern.isEmpty,
count >= pattern.count
else { return }
var stop = false
var lo = startIndex
while !stop && lo < endIndex {
guard
let r = self[lo..<endIndex].range(of: pattern)
else { break }
try body(r, &stop)
lo = r.upperBound
}
}
}
You'll then set stop to true in the body closure once reached the desired occurrence number and capture the range passed to it:
let words = "word1, word1, word2, word3, word1, word3"
var matches = 0
var rangeOfThirdOccurencyOfWord1: Range<String.Index>? = nil
words.enumerateOccurencies(of: "word1") { range, stop in
matches +=1
stop = matches == 3
if stop {
rangeOfThirdOccurencyOfWord1 = range
}
}
Regarding the DFA: recently I've wrote one leveraging on Hashable and using a an Array of Dictionaries as its state nodes, but I've found that the method above is faster, cause maybe range(of:) uses finger-printing.
UPDATE
Otherwise you could also achieve that API you've mentioned in this way:
import Foundation
extension String {
func rangeOfWord(order: Int, separator: String) -> Range<String.Index>? {
precondition(order > 0)
guard
!isEmpty,
!separator.isEmpty,
separator.count < count
else { return nil }
var wordsSoFar = 0
var lo = startIndex
while let r = self[lo..<endIndex].range(of: separator) {
guard
r.lowerBound != lo
else {
lo = r.upperBound
continue
}
wordsSoFar += 1
guard
wordsSoFar < order
else { return lo..<r.lowerBound }
lo = r.upperBound
}
if
lo < endIndex,
wordsSoFar + 1 == order
{
return lo..<endIndex
}
return nil
}
}
let words = "word anotherWord oneMore lastOne"
if let r = words.rangeOfWord(order: 4, separator: " ") {
print(words[r])
} else {
print("not found")
}
Here order parameter refers to the nth order of the word in the string, starting from 1. I've also added the separator parameter to specify a string token to use for finding words in the string (it can also be defaulted to " " to be able to call the function without having to specify it).
Here's my attempt at an updated answer in Swift 5.5:
import Foundation
extension String {
func rangeOfWord(atPosition wordAt: Int) -> Range<String.Index>? {
let fullrange = self.startIndex..<self.endIndex
var count = 0
var foundAt: Range<String.Index>? = nil
self.enumerateSubstrings(in: fullrange, options: .byWords) { _, substringRange, _, stop in
count += 1
if count == wordAt {
foundAt = substringRange
stop = true // Stop the enumeration after the word range is found.
}
}
return foundAt
}
}
let lorem = "Morbi leo risus, porta ac consectetur ac, vestibulum at eros."
if let found = lorem.rangeOfWord(atPosition: 8) {
print("found: \(lorem[found])")
} else {
print("not found.")
}
This solution doesn't make a new array to contain the words so uses less memory (I have not tested but in theory it should use less memory). As much as possible, the build in method is used therefore less chance of bugs.
Swift 5 solution, which allows you to specify the word separator
extension String {
func rangeOfWord(atIndex wordIndex: Int) -> Range<String.Index>? {
let wordComponents = self.components(separatedBy: " ")
guard wordIndex < wordComponents.count else {
return nil
}
let characterEndCount = wordComponents[0...wordIndex].map { $0.count }.reduce(0, +)
let start = String.Index(utf16Offset: wordIndex + characterEndCount - wordComponents[wordIndex].count, in: self)
let end = String.Index(utf16Offset: wordIndex + characterEndCount, in: self)
return start..<end
}
}

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"))