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
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
}
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 } }
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 }
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.
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!)