How to masking textfield in Swift 4? [duplicate] - swift

This question already has answers here:
How to masking the last number in Swift?
(2 answers)
Closed 3 years ago.
I want masking email in textfield.text, but I only get the value in the middle. I want to get the value from the middle to # gmail.com like example below.
ex:
let var = 12345678#gmail.com
output = ****5678#gmail.com
let var = 123456789#gmail.com
output = ****56789#gmail.com
let email = "123456789#gmail.com"
let components = email.components(separatedBy: "#")
let result = hideMidChars(components.first!) + "#" + components.last!
print(result)
output I get: ****5****#gmail.com
my expectations: ****56789#gmail.com

try extending the string protocol and declare a variable which returns an .init(repeating: ,count):
extension StringProtocol {
var masked: String {
return String(repeating: "•", count: Swift.max(0, count - count/2)) + suffix(count/2)
}
}
usage as follows:
let email = "123456789#gmail.com"
print(email.masked) //"••••••••••gmail.com"
if you want a part of the email showing just manipulate the suffix(count - 3) as follows:
return String(repeating: "•", count: Swift.max(0, count - count/2)) + suffix(count/2)

func hide(email: String) -> String {
let parts = email.split(separator: "#")
if parts.count < 2 {
return email
}
let name = parts[0]
let appendix = parts[1]
let lenght = name.count
if lenght == 1 {
return "*#\(appendix)"
}
let semiLenght = lenght / 2
var suffixSemiLenght = semiLenght
if (lenght % 2 == 1) {
suffixSemiLenght += 1
}
let prefix = String(repeating: "*", count: semiLenght)
let lastPart = String(name.suffix(suffixSemiLenght))
let result = "\(prefix)\(lastPart)#\(appendix)"
return result
}
let email = "123456789#gmail.com"
let result = hide(email: email)
print(result)

Related

Random replace using Swift

I am experiencing a problem that I am not sure how to solve and I hope someone here can help me. Currently I have a string variable and later I replace the letters in the string with underscores like the following:
var str = "Hello playground"
let replace = str.replacingOccurrences(of: "\\S", with: "_", options: .regularExpression)
print(str)
Know I would like to randomly generate 25 % of the characters in str (In this case 16 * 0,25 = 4) so it later prints something like these examples:
str = "H__l_ ___yg_____"
str = "_____ play______"
str = "__ll_ ____g____d"
Does anyone have any ideas of how to do this?
A possible solution:
var str = "Hello playground"
print("Before: \(str)")
do {
let regex = try NSRegularExpression(pattern: "\\S", options: [])
let matches = regex.matches(in: str, options: [], range: NSRange(location: 0, length: str.utf16.count))
//Retrieve 1/4 elements of the string
let randomElementsToReplace = matches.shuffled().dropLast(matches.count * 1/4)
matches.forEach({ (aMatch) in
if randomElementsToReplace.first(where: { $0.range == aMatch.range } ) != nil {
str.replaceSubrange(Range(aMatch.range, in: str)!, with: "_")
} else {
//Do nothing because that's the one we are keeping as such
}
})
print("After: \(str)")
} catch {
print("Error while creating regex: \(error)")
}
The idea behind it:
Use the same Regular Expression pattern as the one you used.
Pick up n elements in it (in your case 1/4)
Replace every character that isn't in that short list.
Now that you got the idea, it's even faster replacing the for loop with
for aMatch in randomElementsToReplace {
str.replaceSubrange(Range(aMatch.range, in: str)!, with: "_")
}
Thanks to #Martin R's comment for pointing it out.
Output (done 10 times):
$>Before: Hello playground
$>After: ____o ___y____n_
$>Before: Hello playground
$>After: _el__ _______u__
$>Before: Hello playground
$>After: _e___ ____g___n_
$>Before: Hello playground
$>After: H___o __a_______
$>Before: Hello playground
$>After: H___o _______u__
$>Before: Hello playground
$>After: __l__ _____ro___
$>Before: Hello playground
$>After: H____ p________d
$>Before: Hello playground
$>After: H_l__ _l________
$>Before: Hello playground
$>After: _____ p____r__n_
$>Before: Hello playground
$>After: H___o _____r____
$>Before: Hello playground
$>After: __l__ ___y____n_
You'll see that there is a little difference from your expected result, it's because matches.count == 15, so 1/4 of them should be what? It's up to you there to do the correct calculation according to your needs (round up?, etc.) since you didn't specified it.
Note that if you don't want to round up, you could also do the reverse, use the randomed for the one to not replace, and then the round might play in your favor.
Similarly as in Replace specific characters in string, you can map each character, and combine the result to a string. But now you have to keep track of the (remaining) numbers of non-space characters, and the (remaining) numbers of characters that should be displayed. For each (non-space) character it is randomly decided whether to display (keep) it or to replace it by an underscore.
let s = "Hello playground"
let factor = 0.25
var n = s.filter({ $0 != " " }).count // # of non-space characters
var m = lrint(factor * Double(n)) // # of characters to display
let t = String(s.map { c -> Character in
if c == " " {
// Preserve space
return " "
} else if Int.random(in: 0..<n) < m {
// Keep
m -= 1
n -= 1
return c
} else {
// Replace
n -= 1
return "_"
}
})
print(t) // _e_l_ ______o_n_
This method creates an array of bools that determines which characters will be kept and which will be replaced by using the inbuilt shuffled function.
let string = "Hello playground"
let charsToKeep = string.count / 4
let bools = (Array<Bool>(repeating: true, count: charsToKeep)
+ Array<Bool>(repeating: false, count: string.count - charsToKeep)).shuffled()
let output = zip(string, bools).map
{
char, bool in
return bool ? char : "_"
}
print(String(output))
Edit The above doesn't deal with spaces correctly, but I'll leave it here anyway as a general example.
Here is a version that does deal with the spaces.
let string = "Hello playground and stackoverflow"
let nonSpaces = string.filter{ $0 != " " }.count
let bools = (Array<Bool>(repeating: true, count: nonSpaces / 4) + Array<Bool>(repeating: false, count: nonSpaces - nonSpaces / 4)).shuffled()
var nextBool = bools.makeIterator()
let output = string.map
{
char in
return char == " " ? " " : (nextBool.next()! ? char : "_")
}
print(String(output))
// Hel__ __________ a__ __a____e____w
// ___l_ _l__g_____ _n_ __a_____r__o_
Another possible approach is to generate random indexes for the given string and then replace the characters at those indexes:
var str = "Hello, playground"
let indexes: [Int] = Array(0..<str.count)
let randomIndexes = Array(indexes.shuffled()[0..<(str.count / 4)])
for index in randomIndexes {
let start = str.index(str.startIndex, offsetBy: index)
let end = str.index(str.startIndex, offsetBy: index+1)
str.replaceSubrange(start..<end, with: "_")
}
print(str)
If you put this in a extension on String, it would look like:
extension String {
func randomUnderscores(factor: Double) -> String {
let indexes: [Int] = Array(0..<count)
let endIndexes = Int(Double(count) * factor)
let randomIndexes = Array(indexes.shuffled()[0..<endIndexes])
var randomized = self
for index in randomIndexes {
let start = randomized.index(startIndex, offsetBy: index)
let end = randomized.index(startIndex, offsetBy: index+1)
randomized.replaceSubrange(start..<end, with: "_")
}
return randomized
}
}
print(str.randomUnderscores(factor: 0.25))
I just came up with the following solution:
func generateMyString(string: String) -> String {
let percentage = 0.25
let numberOfCharsToReplace = Int(floor(Double(string.count) * percentage))
let generatedString = stride(from: 0, to: string.count, by: 1).map { index -> String in
return string[string.index(string.startIndex, offsetBy: index)] == " " ? " " : "_"
}.joined()
var newString = generatedString
for i in generateNumbers(repetitions: numberOfCharsToReplace, maxValue: string.count - 1) {
var newStringArray = Array(newString)
newStringArray[i] = Array(string)[i]
newString = String(newStringArray)
}
return newString
}
func generateNumbers(repetitions: Int, maxValue: Int) -> [Int] {
guard maxValue >= repetitions else {
fatalError("maxValue must be >= repetitions for the numbers to be unique")
}
var numbers = [Int]()
for _ in 0..<repetitions {
var n: Int
repeat {
n = Int.random(in: 1...maxValue)
} while numbers.contains(n)
numbers.append(n)
}
return numbers
}
Output:
let str = "Hello playground"
print(generateMyString(string: str)) // ___lo _l_______d
A solution that keeps whitespaces and punctation intact.
We will find them with an extension method indiciesOfPuntationBlanks() -> [Int]. replacing the randomly picked chars will be done by blankOut(percentage: Double) -> String
extension String {
func indiciesOfPuntationBlanks() -> [Int] {
let charSet = CharacterSet.punctuationCharacters.union(.whitespaces)
var indices = [Int]()
var searchStartIndex = self.startIndex
while searchStartIndex < self.endIndex,
let range = self.rangeOfCharacter(from: charSet, options: [], range: searchStartIndex ..< self.endIndex),
!range.isEmpty
{
let index = distance(from: self.startIndex, to: range.lowerBound)
indices.append(index)
searchStartIndex = range.upperBound
}
return indices
}
func blankOut(percentage: Double) -> String {
var result = self
let blankIndicies = result.indiciesOfPuntationBlanks()
let allNonBlankIndicies = Set(0 ..< result.count).subtracting(blankIndicies).shuffled()
let picked = allNonBlankIndicies.prefix(Int(Double(allNonBlankIndicies.count) * percentage))
picked.forEach { (idx) in
let start = result.index(result.startIndex, offsetBy: idx);
let end = result.index(result.startIndex, offsetBy: idx + 1);
result.replaceSubrange(start ..< end, with: "_")
}
return result
}
}
Usage:
let str = "Hello, World!"
for _ in 0 ..< 10 {
print(str.blankOut(percentage: 0.75))
}
Output:
____o, _or__!
_e___, __rl_!
_e__o, __r__!
H____, W_r__!
H_l__, W____!
_____, _or_d!
_e_lo, _____!
_____, _orl_!
_____, _or_d!
___l_, W___d!
Same solution but the string for blanking out and the character sets to be ignored can be configured
extension String {
func indicies(with charSets:[CharacterSet]) -> [Int] {
var indices = [Int]()
let combinedCahrSet: CharacterSet = charSets.reduce(.init()) { $0.union($1) }
var searchStartIndex = self.startIndex
while searchStartIndex < self.endIndex,
let range = self.rangeOfCharacter(from: combinedCahrSet, options: [], range: searchStartIndex ..< self.endIndex),
!range.isEmpty
{
let index = distance(from: self.startIndex, to: range.lowerBound)
indices.append(index)
searchStartIndex = range.upperBound
}
return indices
}
func blankOut(percentage: Double, with blankOutString: String = "_", ignore charSets: [CharacterSet] = [.punctuationCharacters, .whitespaces]) -> String {
var result = self
let blankIndicies = result.indicies(with: charSets)
let allNonBlankIndicies = Set(0 ..< result.count).subtracting(blankIndicies).shuffled()
let picked = allNonBlankIndicies.prefix(Int(Double(allNonBlankIndicies.count) * percentage))
picked.forEach { (idx) in
let start = result.index(result.startIndex, offsetBy: idx);
let end = result.index(result.startIndex, offsetBy: idx + 1);
result.replaceSubrange(start ..< end, with: blankOutString)
}
return result
}
}
Usage:
let str = "Hello, World!"
for _ in 0 ..< 10 {
print(str.blankOut(percentage: 0.75))
}
print("--------------------")
for _ in 0 ..< 10 {
print(str.blankOut(percentage: 0.75, with:"x", ignore: [.punctuationCharacters]))
}
print("--------------------")
for _ in 0 ..< 10 {
print(str.blankOut(percentage: 0.75, with:"*", ignore: []))
}
Output:
_el_o, _____!
__llo, _____!
He__o, _____!
_e___, W_r__!
_el_o, _____!
_el__, ___l_!
_e___, __rl_!
_e__o, _o___!
H____, Wo___!
H____, __rl_!
--------------------
xxxlx,xWxrxx!
xxxxx,xxorxd!
Hxxxx,xWxrxx!
xxxxx, xoxlx!
Hxllx,xxxxxx!
xelxx,xxoxxx!
Hxxxx,xWxxxd!
Hxxxo,xxxxxd!
Hxxxx,xxorxx!
Hxxxx, Wxxxx!
--------------------
***l***Wo**d*
*e**o**W**l**
***lo**Wo****
*el*****or***
H****,****ld*
***l*, **r***
*el*o* ******
*e*lo*******!
H*l****W***d*
H****, **r***
You can use a 3-steps algorithm that does the following:
builds the list of all non-space indices
removes the first 25% random elements from that list
go through all characters and replace all whose index is part of list from #2, by an underscore
The code could look something like this:
func underscorize(_ str: String, factor: Double) -> String {
// making sure we have a factor between 0 and 1
let factor = max(0, min(1, factor))
let nonSpaceIndices = str.enumerated().compactMap { $0.1 == " " ? nil : $0.0 }
let replaceIndices = nonSpaceIndices.shuffled().dropFirst(Int(Double(str.count) * factor))
return String(str.enumerated().map { replaceIndices.contains($0.0) ? "_" : $0.1 })
}
let str = "Hello playground"
print(underscorize(str, factor: 0.25))
Sample results:
____o p_ay______
____o p__y____n_
_el_o p_________
The idea is same as above methods, just with a little less code.
var str = "Hello playground"
print(randomString(str))
print(randomString(str))
// counting whitespace as a random factor
func randomString(_ str: String) -> String{
let strlen = str.count
let effectiveCount = Int(Double(strlen) * 0.25)
let shuffled = (0..<strlen).shuffled()
return String(str.enumerated().map{
shuffled[$0.0] < effectiveCount || ($0.1) == " " ? ($0.1) : "_"
})}
//___l_ _l__gr____
//H____ p___g____d
func underscorize(_ str: String) -> String{
let effectiveStrlen = str.filter{$0 != " "}.count
let effectiveCount = Int(floor(Double(effectiveStrlen) * 0.25))
let shuffled = (0..<effectiveStrlen).shuffled()
return String((str.reduce(into: ([],0)) {
$0.0.append(shuffled[$0.1] <= effectiveCount || $1 == " " ? $1 : "_" )
$0.1 += ($1 == " ") ? 0 : 1}).0)
}
print(underscorize(str))
print(underscorize(str))
//__l__ pl__g_____
//___lo _l_______d
First you need to get the indices of your string and filter the ones that are letters. Then you can shuffle the result and pick the number of elements (%) minus the number of spaces in the original string, iterate through the result replacing the resulting ranges with the underscore.
You can extending RangeReplaceable protocol to be able to use it with substrings as well:
extension StringProtocol where Self: RangeReplaceableCollection{
mutating func randomReplace(characterSet: CharacterSet = .letters, percentage: Double, with element: Element = "_") {
precondition(0...1 ~= percentage)
let indices = self.indices.filter {
characterSet.contains(self[$0].unicodeScalars.first!)
}
let lettersCount = indices.count
let nonLettersCount = count - lettersCount
let n = lettersCount - nonLettersCount - Int(Double(lettersCount) * Double(1-percentage))
indices
.shuffled()
.prefix(n)
.forEach {
replaceSubrange($0...$0, with: Self([element]))
}
}
func randomReplacing(characterSet: CharacterSet = .letters, percentage: Double, with element: Element = "_") -> Self {
precondition(0...1 ~= percentage)
var result = self
result.randomReplace(characterSet: characterSet, percentage: percentage, with: element)
return result
}
}
// mutating test
var str = "Hello playground"
str.randomReplace(percentage: 0.75) // "___lo _l___r____\n"
print(str) // "___lo _l___r____\n"
// non mutating with another character
let str2 = "Hello playground"
str2.randomReplacing(percentage: 0.75, with: "•") // "••••o p••y•••u••"
print(str2) // "Hello playground\n"

hide some numbers with star in phone number UIlabel using for otp verification swift 4 app

i am making an app in swift 4 and i want the enetered number label text to show something like this when otp is sent
" otp is sent to +91******21 "
here is the thing I found now I don't own what logic should be applied here to post string like that
var mobileNumer = "+91987654321"
let intLetters = mobileNumer.prefix(3)
let endLetters = mobileNumer.suffix(2)
i want this tpe of number to be shown on the label after enytering the mobile number , it should show frist two numbers then start and hen show last two numbers
try this:
var mobileNumer = "+91987654321"
let intLetters = mobileNumer.prefix(3)
let endLetters = mobileNumer.suffix(2)
let newString = intLetters + "*******" + endLetters //"+91*******21"
Or if you want to be safe:
var mobileNumer = "+91987654321"
guard mobileNumer.count > 5 else {
fatalError("The phone number is not complete")
}
let intLetters = mobileNumer.prefix(3)
let endLetters = mobileNumer.suffix(2)
let stars = String(repeating: "*", count: mobileNumer.count - 5)
let result = intLetters + stars + endLetters
Or if you'd prefer to replace a subrange:
var mobileNumer = "+91987654321"
guard mobileNumer.count > 5 else {
fatalError("The phone number is not complete")
}
let startingIndex = mobileNumer.index(mobileNumer.startIndex, offsetBy: 3)
let endingIndex = mobileNumer.index(mobileNumer.endIndex, offsetBy: -2)
let stars = String(repeating: "*", count: mobileNumer.count - 5)
let result = mobileNumer.replacingCharacters(in: startingIndex..<endingIndex,
with: stars)
Or
If you'd like to mutate mobileNumer:
mobileNumer.replaceSubrange(startingIndex..<endingIndex, with: stars)
print(mobileNumer) //"+91*******21"
You can use this function.
func starifyNumber(number: String) -> String {
let intLetters = number.prefix(3)
let endLetters = number.suffix(2)
let numberOfStars = number.count - (intLetters.count + endLetters.count)
var starString = ""
for _ in 1...numberOfStars {
starString += "*"
}
let finalNumberToShow: String = intLetters + starString + endLetters
return finalNumberToShow
}
To call it
let mobileNumer = starifyNumber(number: "+91987654321")
print(mobileNumer) \\+91*******21

How do I search for a range of Strings [duplicate]

This question already has answers here:
Extracting the RGB value from a string
(2 answers)
Closed 4 years ago.
How do I search for a range of Strings,
I want to search userID
But userID may this time is "123",
next time is "zxvcvb",
so i can't use offsetBy
let userID = "12345"
let URL = "http://test/main/?Username=\(userID)#!/index.php"
let firstIndex = URL.index(of: "=")
let secondIndex = URL.index(of: "#")
let range = firstIndex...secondIndex //error
Try this code :
let userID = "jshjdschd"
let url = "http://test/main/?Username=\(userID)#!/index.php"
guard let firstIndex = url.index(of: "="),
let secondIndex = url[firstIndex...].index(of: "#") else{
print("UserId not found")
}
let range = url.index(after: firstIndex)..<secondIndex
let mySubstring = url[range]
print(mySubstring) //jshjdschd
You can use a regex to get the range of the user ID between those two strings:
let userID = "12345"
let pattern = "(?<=Username=)(.*)(?=#!)"
let link = "http://test/main/?Username=\(userID)#!/index.php"
if let range = link.range(of: pattern, options: .regularExpression) {
let id = link[range]
print("id:", id) // "id: 12345\n"
}

How to get `printf` to work as expected using Swift String? [duplicate]

What I'm wanting to do is very simple in C/C++, Java, and so many other languages. All I want to do is be able to specify the width of a string, similar to this:
printf("%-15s", var);
This would create of a field width of 15 characters. I've done a lot of googling. I've tried using COpaquepointeras well as String(format:in various ways with no luck. Any suggestions would be greatly appreciated. I could have missed something when googling.
You can use withCString to quickly convert the string to an array of bytes (technically an UnsafePointer<Int8>):
let str = "Hello world"
let formatted = str.withCString { String(format: "%-15s", $0) }
print("'\(formatted)'")
You are better to do it yourself
let str0 = "alpha"
let length = 20
// right justify
var str20r = String(count: (length - str0.characters.count), repeatedValue: Character(" "))
str20r.appendContentsOf(str0)
// " alpha"
// left justify
var str20l = str0
str20l.appendContentsOf(String(count: (length - str0.characters.count), repeatedValue: Character(" ")))
// "alpha "
if you need something 'more general'
func formatString(str: String, fixLenght: Int, spacer: Character = Character(" "), justifyToTheRigth: Bool = false)->String {
let c = str.characters.count
let start = str.characters.startIndex
let end = str.characters.endIndex
var str = str
if c > fixLenght {
switch justifyToTheRigth {
case true:
let range = start.advancedBy(c - fixLenght)..<end
return String(str.characters[range])
case false:
let range = start..<end.advancedBy(fixLenght - c)
return String(str.characters[range])
}
} else {
var extraSpace = String(count: fixLenght - c, repeatedValue: spacer)
if justifyToTheRigth {
extraSpace.appendContentsOf(str)
return extraSpace
} else {
str.appendContentsOf(extraSpace)
return str
}
}
}
let str = "ABCDEFGH"
let s0 = formatString(str, fixLenght: 3)
let s1 = formatString(str, fixLenght: 3, justifyToTheRigth: true)
let s2 = formatString(str, fixLenght: 10, spacer: Character("-"))
let s3 = formatString(str, fixLenght: 10, spacer: Character("-"), justifyToTheRigth: true)
print(s0)
print(s1)
print(s2)
print(s3)
which prints
ABC
FGH
ABCDEFGH--
--ABCDEFGH
The problem is that Swift strings have variable size elements, so it's ambiguous what "15 characters" is. This is a source of frustration for simple strings — but makes the language more precise when dealing with emoji, regional identifiers, ligatures, etc.
You can convert the Swift string to a C-string and use normal formatters (see Santosh's answer). The "Swift" way to handle strings is to begin at the starting index of the collection of Characters and advance N times. For example:
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let index = alphabet.characters.startIndex.advancedBy(14) // String.CharacterView.Index
let allChars = alphabet.characters.prefixThrough(index) // String.CharacterView
print(String(allChars)) // "ABCDEFGHIJKLMNO\n"
If you want to force padding, you could use an approach like this:
extension String {
func formatted(characterCount characterCount:Int) -> String {
if characterCount < characters.count {
return String(characters.prefixThrough(characters.startIndex.advancedBy(characterCount - 1)))
} else {
return self + String(count: characterCount - characters.count, repeatedValue: " " as Character)
}
}
}
let abc = "ABC"
let alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
print("!\(abc.formatted(characterCount: 15))!")
// "!ABC !\n"
print("!\(alphabet.formatted(characterCount: 15))!")
// "!ABCDEFGHIJKLMNOP!\n"
Did you try this?
let string1 = "string1"
let string2 = "string2"
let formattedString = String(format: "%-15s - %s",
COpaquePointer(string1.cStringUsingEncoding(NSUTF8StringEncoding)!),
COpaquePointer(string2.cStringUsingEncoding(NSUTF8StringEncoding)!)
)
print(formattedString)
//string1 - string2
We've got a ton of interesting answers now. Thank you everyone. I wrote the following:
func formatLeftJustifiedWidthSpecifier(stringToChange: String, width: Int) -> String {
var newString: String = stringToChange
newString = newString.stringByPaddingToLength(width, withString: " ", startingAtIndex: 0)
return newString
}
From one hand %# is used to format String objects:
import Foundation
var str = "Hello"
print(String(format: "%#", str))
But it does not support the width modifier:
print(String(format: "%-15#", str))
Will still print unpadded text:
"Hello\n"
However there is a modifier %s that seems to work with CStrings:
var cstr = (str as NSString).utf8String //iOS10+ or .UTF8String otherwise
print(String(format: "%-15s", cstr!))
Output:
"Hello \n"
One nice thing is that you can use the same format specification with NSLog:
NSLog("%-15s", cstr!)
To augment the answer above by "Code Different" (thank you!) on Jun 29, 2016, and allow to write something like "hello".center(42); "world".alignLeft(42):
extension String {
// note: symbol names match to nim std/strutils lib
func align (_ boxsz: UInt) -> String {
self.withCString { String(format: "%\(boxsz)s", $0) }
}
func alignLeft (_ boxsz: UInt) -> String {
self.withCString { String(format: "%-\(boxsz)s", $0) }
}
func center (_ boxsz: UInt) -> String {
let n = self.count
guard boxsz > n else { return self }
let padding = boxsz - UInt(n)
let R = padding / 2
guard R > 0 else { return " " + self }
let L = (padding%2 == 0) ? R : (R+1)
return " ".withCString { String(format: "%\(L)s\(self)%\(R)s", $0,$0) }
}
}

Calculate count of years

I have a String data that stores date. Example:
let dates = ["1-Jan-2015", "1-Feb-2015", "20-Mar-2014", "15-Apr-2014", "12-May-2013", "23-Jun-2012"]
I need to do a count of how many times did that year occurs, and then store it. So what I require would be something like that
let years = ["2015" : 2, "2014" : 2, "2013" : 1, "2012" : 1]
I would like to avoid hard coding it for future growth. Meaning say if I have Year 2020, I cannot be hard coding all the years to store these values.
So the problem here is I've got no idea how should I do this on the overview. In addition, how do I convert the String format to date?
let dates = ["1-Jan-2015", "1-Feb-2015", "20-Mar-2014", "15-Apr-2014", "12-May-2013", "23-Jun-2012"]
// map the last 4 characters of your string
let years = dates.map{String($0.characters.suffix(4))}
// create a dictionary to store tue frequency
var frequencies:[String:Int] = [:]
// loop through the years
for year in years {
// increase it
frequencies[year] = (frequencies[year] ?? 0) + 1
}
let sortedFrequencies = frequencies.sort{ $0.0 < $1.0 }
print(sortedFrequencies) // [("2012", 1), ("2013", 1), ("2014", 2), ("2015", 2)]\n"
I have created the following solution. Use the following function and it will give you the following result in the screenshot
/// This function will return the array as per your requirement
func getyears(dates: NSArray) -> NSArray
{
var year = [String]()
let newdates = dates
var countvalue = 0
for i in dates {
let x = i.stringByReplacingOccurrencesOfString("-", withString: "")
let startIndex = x.endIndex.advancedBy(-4)
let lastFourDigitsOfdate = x.substringFromIndex(startIndex)
for xm in newdates
{
let xy = xm.stringByReplacingOccurrencesOfString("-", withString: "")
let startIndex1 = xy.endIndex.advancedBy(-4)
let lastFourDigitsOfdate1 = xy.substringFromIndex(startIndex1)
if lastFourDigitsOfdate == lastFourDigitsOfdate1
{
countvalue = countvalue + 1
}
}
year.append("\(lastFourDigitsOfdate) : \(countvalue)")
countvalue = 0
}
return getUniqArrayData(year)
}
// This function will be required to get an unque array
func getUniqArrayData<S: SequenceType, E: Hashable where E==S.Generator.Element>(source: S) -> [E] {
var seen: [E:Bool] = [:]
return source.filter { seen.updateValue(true, forKey: $0) == nil }
}
let dates = ["1-Jan-2015", "1-Feb-2015", "20-Mar-2014", "15-Apr-2014", "12-May-2013", "23-Jun-2012"]
//Calling the above function
getyears(dates)
Hope this will be helpful.