Convert String containing Array of Integer to Integer Array IN Swift - arrays

I have a
let locationjson: String = "[\"43786\",\"55665\",\"62789\",\"90265\"]"
And I want to convert it to Arraylist / List in Swift... I have searched on StackOverflow but couldn't find an appropriate solution for Swift.
I want to output as List<Integer> containing the values [43786,55665,62789,90265].

As Martin mentioned in the comments JSONSerialization is your friend:
let locationjson = "[\"43786\",\"55665\",\"62789\",\"90265\"]"
let data = locationjson.data(using: .utf8)!
if let array = (try? JSONSerialization.jsonObject(with: data)) as? [String] {
let intArray = array.flatMap { Int($0) }
print(intArray)
}

You can do this using flatMap:
let locationjson = ["43786", "55665", "62789", "90265"]
let result = locationjson.flatMap { Int($0) }

You mean something like this?
var str:String = "[\"1\",\"2\",\"3\",\"4\",\"5\",\"6\"]"
str = str.replacingOccurrences(of: "[", with: "")
str = str.replacingOccurrences(of: "]", with: "")
str = str.replacingOccurrences(of: "\"", with: "")
var arrStrNums = str.components(separatedBy: ",")
var nums:[Int] = []
for strNum in arrStrNums {
if let num = Int(strNum) {
nums.append(num)
}
}
print("Number list: \(nums)")
Outputs:
Number list: [1, 2, 3, 4, 5, 6]

Related

Mexican wave in Swift string

I need to print a String as if a Mexican Wave is passing through each character in the String:
wave("hello") -> ["Hello", "hEllo", "heLlo", "helLo", "hellO"]
For current moment I'm stopped at:
var str = "hel lo"
var arr = [String]()
str = str.lowercased()
str = str.replacingOccurrences(of: " ", with: "")
for i in str {
arr.append (str.replacingOccurrences(of: "\(i)", with: i.uppercased()))
}
print(arr)
You can simply map your string indices and replace its character at each iteration:
let string = "hello"
let result = string.indices.map {
string.replacingCharacters(in: $0...$0, with: string[$0...$0].uppercased())
}
print(result)
This will print:
["Hello", "hEllo", "heLlo", "helLo", "hellO"]
After many iterations and doc reviews, also find this solution:
func wave(_ y: String) -> [String] {
if y.count == 0 {
return [String]()
}
var wave = [String]()
for i in y.indices {
if !y[i].isWhitespace{
wave.append(y[..<i] + y[i].uppercased() + y[y.index(after: i)...])
}
}
return wave
}

Does Swift offer any built-in function to return the result of appending to an immutable array?

Writing the question and answer from here, I'm curious to know if there is any simpler way to write the following:
var nums = [1,2,3]
let sum1 = nums.reduce([Int]()){
let temp = $0
temp.append($1)
return temp
}
I know I can do:
var nums = [1,2,3]
let sum1 = nums.reduce([Int]()){
return $0 + [$1]
}
But that comes off as a hack.
To explain this better, I want to get closer to the example (from docs) below, just that it should be for an array:
let numbers = [1, 2, 3, 4]
let numberSum = numbers.reduce(0, { x, y in
x + y
})
EDIT:
Since folks asked what was I trying to achieve:
I was doing the leetcode's group Anagram's challenge.
My solution was:
struct WordTraits: Equatable{
let count: Int
let charactersSet: Set<Character>
}
struct Word: Equatable{
let string: String
let wordTraits: WordTraits
}
class Solution{
func groupAnagrams(_ strs: [String]) -> [[String]]{
var words : [Word] = []
var answers : [(traits: WordTraits, words: [Word])] = []
var count = 0
strs.forEach{ str in
count += 1
let count = str.count
let string = str
let characterSet = Set(str)
let wordTraits = WordTraits(count: count, charactersSet: characterSet)
let word = Word(string: string, wordTraits: wordTraits)
words.append(word)
}
while words.count != 0{
let word = words[0]
let traits = word.wordTraits
var isWordAdded = false
for (i, answer) in answers.enumerated(){
if answer.traits == traits{
answers[i].words.append(word)
isWordAdded = true
break
}
}
if !isWordAdded{
answers.append((traits: traits, words:[word]))
}
words.removeFirst()
}
let emptyArray : [[String]] = []
let finalAnswer = answers.reduce(emptyArray, { total, answer in
let strings : [String] = answer.words.reduce([String](), {
return $0 + [$1.string]
})
return total + [strings]
})
return finalAnswer
}
}
let s = Solution()
print(s.groupAnagrams(["ate", "eta", "beta", "abet"])) // [["ate", "eta"], ["beta", "abet"]]
reduce(..) has to know which type it is working with. To infer this it can use the return type or the type of the first argument. So you can also write:
var nums = [1,2,3]
let sum1: [Int] = nums.reduce([]){
return $0 + [$1]
}
[$1] can't be replaced with $1 because +-operator between value and collection is undefined.
Nope. But you can add it:
extension Array {
func appending(_ newElement: Element) -> Array<Element> {
return self + [newElement]
}
func appending(contentsOf sequence: Sequence) -> Array<Element> {
return self + sequence
}
}
Um, how about the + operator?
let nums = [1, 3, 5]
let more = nums + [7]
Your code is trying to convert a complex structure to an array of arrays. You can use map for this.
This should work:
let finalAnswer = answers.map { answer in
answer.words.map {
$0.string
}
}
Edit:
I was able to solve it using minimal code:
class Solution {
func groupAnagrams(_ words: [String]) -> [[String]] {
let processedWords = words.map {
(key: String($0.sorted()), value: $0)
}
return Dictionary(grouping: processedWords, by: { $0.key }).map { groupedValue in
groupedValue.value.map {
$0.value
}
}
}
}
You've greatly overcomplicated your computation of "final answers". It could just be:
return answers.map { $0.words.map { $0.string } }

Filtering Dictionary with an array of random Ints to make a new dict

So I have this method to get an array of random ints between 1-9, a random number of times between 1 and 7.
let n = arc4random_uniform(7) + 1
var arr: [UInt32] = []
for _ in 0 ... n {
var temp = arc4random_uniform(9) + 1
while arr.contains(temp) {
temp = arc4random_uniform(9) + 1
}
print(temp)
arr.append(temp)
}
print(arr)
So that gets me an array like [1,4,2] or [5,7,3,4,6]. And I have a method to turn another array of strings into a enumerated dictionary.
var someArray: [String] = ["War", "Peanuts", "Cats", "Dogs", "Nova", "Bears", "Pigs", "Packers", "Mango", "Turkey"]
extension Collection {
var indexedDictionary: [Int: Element] {
return enumerated().reduce(into: [:]) { $0[$1.offset] = $1.element }
}
}
let dict1 = someArray.indexedDictionary
print(dict1)
giving me the indexed dictionary
[1:"War", 2:"Peanuts",..etc]
MY question is using the Ints of the random array how do I create a new dictionary that only includes those keys and their values?
So for example if arr = [3,1,5]
how do I get a new dictionary of
[3:"dogs", 1:"Peanuts",5:"Bears"].
This should do it:
let finalDict = dict1.filter { arr.contains($0.key) }
Update:
You can even go a step further and skip the whole strings to array mapping. So remove
extension Collection {
var indexedDictionary: [Int: Element] {
return enumerated().reduce(into: [:]) { $0[$1.offset] = $1.element }
}
}
let dict1 = someArray.indexedDictionary
print(dict1)
and just use this:
Swift 4:
let finalArray = someArray.enumerated().flatMap { arr.contains($0.offset) ? $0.element : nil }
Swift 4.1:
let finalArray = someArray.enumerated().compactMap { arr.contains($0.offset) ? $0.element : nil }
Update 2:
If you need a dictionary and not an array in the end use this:
Swift 4:
let finalDict = someArray.enumerated().flatMap { randomInts.contains($0.offset) ? ($0.offset, $0.element) : nil }.reduce(into: [:]) { $0[$1.0] = $1.1 }
Swift 4.1:
let finalDict = someArray.enumerated().compactMap { randomInts.contains($0.offset) ? ($0.offset, $0.element) : nil }.reduce(into: [:]) { $0[$1.0] = $1.1 }

how to combine two dictionary values as a key and value pair in swift

let arra = ["abc","def","abc","def"]
let arra2 = ["addr1","addr2","addr1","addr2"]
Expected Output
dic = ["abc":"addr1","addr1" , def: "addr2","addr2"]
Swift 4's new Dictionary initializer lets you do that kind of thing easily:
let arra = ["abc","def","abc","def"]
let arra2 = ["addr1","addr2","addr1","addr2"]
let dict = [String:[String]](zip(arra,arra2.map{[$0]}),uniquingKeysWith:+)
print(dict) // ["abc": ["addr1", "addr1"], "def": ["addr2", "addr2"]]
[EDIT] Swift 3 equivalent :
var dict : [String:[String]] = [:]
zip(arra,arra2.map{[$0]}).forEach{ dict[$0] = (dict[$0] ?? []) + $1 }
There should be easier way but in general:
import UIKit
let keyArray = ["abc","def","abc","def"]
let valueArray = ["addr1","addr2","addr1","addr2"]
let setFromKeyArray = Set(keyArray)
var finalDict = [String: [String]]()
for index in 0..<keyArray.count {
if let _ = finalDict[keyArray[index]] {
finalDict[keyArray[index]]!.append(valueArray[index])
} else {
finalDict[keyArray[index]] = [valueArray[index]]
}
}
print(finalDict)
// output: ["abc": ["addr1", "addr1"], "def": ["addr2", "addr2"]]
Using zip(_:_:) and reduce(_:_:):
let array1 = ["abc", "def", "abc", "def"]
let array2 = ["addr1", "addr2", "addr1", "addr2"]
let dictionary = zip(array1, array2).reduce([String: String]()) {
var dictionary = $0
dictionary[$1.0] = $1.1
return dictionary
}
print(dictionary) // ["abc": "addr1", "def": "addr2"]
You can use like below :
let arra = ["abc","def","abc","def"]
let arra2 = ["addr1","addr2","addr1","addr2"]
var dictionary: [String: String] = [:]
dictionary.merge(zip(arra, arra2)) { (old, new) -> String in
return "\(old), \(new)"
}
print(dictionary)
Output :
["abc": "addr1, addr1", "def": "addr2, addr2"]
The best of Dennis and Kristijan and Alain.
let arra = ["abc", "def", "abc", "def"]
let arra2 = ["addr1", "addr2", "addr1", "addr2"]
let dict = zip(arra, arra2).reduce([String:[String]]()){
var d = $0
d[$1.0] = ($0[$1.0] ?? []) + [$1.1]
return d
}
print(dict) // ["def": ["addr2", "addr2"], "abc": ["addr1", "addr1"]]
Remember dictionary is unordered.

Convert Array<String> to String then back to Array<String>

say I have a variable
let stringArray = "[\"You\", \"Shall\", \"Not\", \"PASS!\"]"
// if I show this, it would look like this
print(stringArray)
["You", "Shall", "Not", "PASS!"]
now let's have an Array< String>
let array = ["You", "Shall", "Not", "PASS!"]
// if I convert this into string
// it would roughly be equal to the variable 'stringArray'
if String(array) == stringArray {
print("true")
} else {
print("false")
}
// output would be
true
now say what should I do to convert variable 'stringArray' to 'Array< String>'
The answer would be to convert the string using NSJSONSerialization
Thanks Vadian for that tip
let dataString = stringArray.dataUsingEncoding(NSUTF8StringEncoding)
let newArray = try! NSJSONSerialization.JSONObjectWithData(dataString!, options: []) as! Array<String>
for string in newArray {
print(string)
}
voila there you have it, it's now an array of strings
A small improvement for Swift 4.
Try this:
// Array of Strings
let array: [String] = ["red", "green", "blue"]
let arrayAsString: String = array.description
let stringAsData = arrayAsString.data(using: String.Encoding.utf16)
let arrayBack: [String] = try! JSONDecoder().decode([String].self, from: stringAsData!)
For other data types respectively:
// Set of Doubles
let set: Set<Double> = [1, 2.0, 3]
let setAsString: String = set.description
let setStringAsData = setAsString.data(using: String.Encoding.utf16)
let setBack: Set<Double> = try! JSONDecoder().decode(Set<Double>.self, from: setStringAsData!)

Resources