Related
I've an array of dictionary with something like this:
[["XL":956], ["M":1010], ["S":998], ["L":955], ["XXL":921], ["XS":1041], ["30":45], ["28":41], ["32":46], ["26":35], ["34":50], ["One Size":1]]
How do I sort it so that it is in this order?
[["XS":1041], ["S":998], ["M":1010], ["L":955], ["XL":956], ["XXL":921], ["26":35], ["28":41], ["30":45], ["32":46], ["34":50], ["One Size":1]]
Note that every size is not always present, it's dynamic
If you're confident about knowing all of your size strings, and so happy to force unwrap, you can do it in a one-liner.
let order = ["XS", "S", "M", "L", "XL", "XXL", "26", "28", "30", "32", "34", "One Size"]
let sorted = sizes.sorted{order.firstIndex(of: $0.first!.key)! < order.firstIndex(of: $1.first!.key)!}
Depending on where you are going to use this, the better option would be to unwrap the optionals safely in case of bad data! :-)
Create a reference array that contains the alphabetical sizes in sorted order.
Now, sort the array based on reference array, i.e.
let data = [["XL":956], ["M":1010], ["S":998], ["L":955], ["XXL":921], ["XS":1041], ["30":45], ["28":41], ["32":46], ["26":35], ["34":50], ["One Size":1]]
let ref = ["XS", "S", "M", "L", "XL", "XXL"]
let result = data.sorted { (val1, val2) -> Bool in
if let key1 = val1.first?.key, let key2 = val2.first?.key {
if let x = Int(key1), let y = Int(key2) {
return x < y
} else if let x = ref.firstIndex(of: key1), let y = ref.firstIndex(of: key2) {
return x < y
} else {
return ref.firstIndex(of: key1) != nil
}
}
return false
}
This question already has answers here:
How to merge two arrays in Swift
(3 answers)
Closed 3 years ago.
I have two array like below. I need to combine two array each data and append to one array. The example are :
var d1 = ["1", "2", "3", "4", "5"]
var d2 = ["A", "B", "C", "D", "E"]
var d3 = [String]()
//O/P needed : ["1-A","2-B","3-C","4-D","5-E"]
Any help would be great.
Thanks
Use a combination of zip(_:_:) and map(_:) over d1 and d2 like so,
let d3 = zip(d1, d2).map({ $0.0 + "-" + $0.1})
print(d3) //["1-A", "2-B", "3-C", "4-D", "5-E"]
In case any one of the arrays have extra elements, those extra ones will be ignored while performing the zip operation.
var d1 = ["1", "2", "3", "4", "5"]
var d2 = ["A", "B", "C", "D", "E"]
var d3 = [String]()
//O/P needed : ["1-A","2-B","3-C","4-D","5-E"]
// works for diff length of d2
func mergArray(firstArray: [String], secondArray: [String]) -> [String] {
for (index,val) in d1.enumerated() {
guard index < d2.count else {
d3.append(val)
return d3
}
d3.append(val + "-" + d2[index])
}
return d3
}
print(mergArray(firstArray: d1, secondArray: d2))
Do it like -
for i in 0..< d1.count {
d3.append(d1[i] + "-" + d2[i])
}
print(d3)
You will have your desire result.
I have a problem to sort some numbers, which are string first. The numbers are too huge for UInt64, so i converted the string numbers to float and then sorted it. That works out great. But then i need to print these numbers with no decimals. So I tried to format the numbers. But the Bigger number are changing its value after formatting it.
Here is the Input array to sort -
["6","31415926535897932384626433832795","1","3","10","3","5"]
And I need to print output in exactly this format -
1
3
3
5
10
31415926535897932384626433832795
Here is my code in swift -
import Foundation
var a = Array<Float>()
var b = ["6","31415926535897932384626433832795","1","3","10","3","5"]
a = b.map{ Float($0)! }
for i in 0..<(a.count-1){
var min = i
for j in (i+1)..<a.count{
if a[j] < a[min] {
min = j
}
}
var temp = a[i]
a[i] = a[min]
a[min] = temp
}
for val in a{
print(String(format: "%.0f",val.rounded(.down)))
}
My Output is -
1
3
3
5
6
10
31415927314585224784361549725696
If you notice the last biggest number is changed from the original input. Any suggestions would be much appreciated! Thanks!
You can use numeric comparison:
let values = ["6","31415926535897932384626433832795","1","3","10","3","5"]
let sortedValues = values.sorted { (value1, value2) in
let order = value1.compare(value2, options: .numeric)
return order == .orderedAscending
}
print(sortedValues) // ["1", "3", "3", "5", "6", "10", "31415926535897932384626433832795"]
With using float, you may get unexpected result for orders between big ints:
var str = "Hello, playground"
let inArray = [
"6",
"31415926535897932384626433832797",
"31415926535897932384626433832796",
"31415926535897932384626433832795",
"1",
"3"
]
let outArray = inArray.sorted {Float($0)! < Float($1)!}
print(outArray)
//->["1", "3", "6", "31415926535897932384626433832797", "31415926535897932384626433832796", "31415926535897932384626433832795"]
As described in mag_zbc's answer, Float has about only 7 significant digits, so all less significant digits are lost.
Float("31415926535897932384626433832797") == Float("31415926535897932384626433832795")
//->true
If the digits of your numbers are 38 at most, you can use Decimal (as also suggested in mag_zbc's answer).
let outWithDecimal = inArray.sorted {Decimal(string: $0)! < Decimal(string: $1)!}
print(outWithDecimal)
//->["1", "3", "6", "31415926535897932384626433832795", "31415926535897932384626433832796", "31415926535897932384626433832797"]
Or else, if your data contains numbers with more than 38 digits, String comparison would work with a little pre-processing:
(Assuming all your numbers are non-negative integer.)
extension String {
func fillZeroLeft(_ length: Int) -> String {
if self.characters.count < length {
return String.init(repeating: "0", count: length-self.characters.count) + self
} else {
return self
}
}
}
let maxLen = inArray.lazy.map{$0.characters.count}.max()!
let outWithString = inArray.sorted {$0.fillZeroLeft(maxLen) < $1.fillZeroLeft(maxLen)}
print(outWithString)
//->["1", "3", "6", "31415926535897932384626433832795", "31415926535897932384626433832796", "31415926535897932384626433832797"]
(But numeric comparison in Sulthan's answer seems to be better for me!)
It's impossible to accurately represent such big numbers using primitive types in Swift.
Your value is ~3e+32
UInt64 has a max value of ~1,8e+18
Float uses 24 bits for a significant, which allows to accurately represent a number up to ~1.6e+8
Double uses 53 bits for significant, which allows to accurately represent a number up to ~9e+15
Floating point types (Float and Double) are able to hold much greater values, but they will lose accuracy above the numbers their significants can hold.
Apart from using some external library, I'd suggest using NSDecimalNumber class, which is supposed to be able to hold up to 38 decimal digits - which is enough for numbers in your example. However, if you need even bigger numbers, then you'll need to look for some external library.
I am trying to convert a String into a Double value in Swift. After doing a lot of research, I believe that this would be the best method to turn my string to an Double. But now I am getting an error that I have no idea of how to fix.
var purchaseAmount: Double = 200
var cashTendered: Double = 425.45
var changeRequired: Double = 0
var currencyValues = ["100", "50", "20", "10", "5", "2", "1", "0.50", "0.20", "0.10", "0.05"]
import Cocoa
if cashTendered < purchaseAmount {
println("Not enough cash tendered")
} else {
changeRequired = cashTendered - purchaseAmount
for currency in currencyValues {
var doubleCurrency = (currency as NSString).doubleValue
var amountOfCurrency = changeRequired / doubleCurrency
amountOfCurrency = floor(amountOfCurrency)
changeRequired = changeRequired - (amountOfCurrency * currency)
changeRequired = round(changeRequired * 100)/100
println("$\(currency) X \(Int(amountOfCurrency))")
}
}
Here is the error:
What do I have to do to solve this problem?
First of all initialise String array like below:
let currencyValues : [String] = ["100", "50", "20", "10", "5", "2", "1", "0.50", "0.20", "0.10", "0.05"]
However it is not required type declaration because of Swift has vital feature Type Interface. But most of the practice it is good to define type while working with array.
And about converting string to double you can use below code:
for currency : String in currencyValues {
let doubleCurrency = NSNumberFormatter().numberFromString(currency)!.doubleValue
print(doubleCurrency)
}
Posting code would be easier to look at than an image, but if all else fails there is NSNumberFormatter. Other advantage of NSNumberFormatter would allow you to convert both directions and get nice output for things like currency.
How can I convert a String "Hello" to an Array ["H","e","l","l","o"] in Swift?
In Objective-C I have used this:
NSMutableArray *characters = [[NSMutableArray alloc] initWithCapacity:[myString length]];
for (int i=0; i < [myString length]; i++) {
NSString *ichar = [NSString stringWithFormat:#"%c", [myString characterAtIndex:i]];
[characters addObject:ichar];
}
It is even easier in Swift:
let string : String = "Hello 🐶🐮 🇩🇪"
let characters = Array(string)
println(characters)
// [H, e, l, l, o, , 🐶, 🐮, , 🇩🇪]
This uses the facts that
an Array can be created from a SequenceType, and
String conforms to the SequenceType protocol, and its sequence generator
enumerates the characters.
And since Swift strings have full support for Unicode, this works even with characters
outside of the "Basic Multilingual Plane" (such as 🐶) and with extended grapheme
clusters (such as 🇩🇪, which is actually composed of two Unicode scalars).
Update: As of Swift 2, String does no longer conform to
SequenceType, but the characters property provides a sequence of the
Unicode characters:
let string = "Hello 🐶🐮 🇩🇪"
let characters = Array(string.characters)
print(characters)
This works in Swift 3 as well.
Update: As of Swift 4, String is (again) a collection of its
Characters:
let string = "Hello 🐶🐮 🇩🇪"
let characters = Array(string)
print(characters)
// ["H", "e", "l", "l", "o", " ", "🐶", "🐮", " ", "🇩🇪"]
Edit (Swift 4)
In Swift 4, you don't have to use characters to use map(). Just do map() on String.
let letters = "ABC".map { String($0) }
print(letters) // ["A", "B", "C"]
print(type(of: letters)) // Array<String>
Or if you'd prefer shorter: "ABC".map(String.init) (2-bytes 😀)
Edit (Swift 2 & Swift 3)
In Swift 2 and Swift 3, You can use map() function to characters property.
let letters = "ABC".characters.map { String($0) }
print(letters) // ["A", "B", "C"]
Original (Swift 1.x)
Accepted answer doesn't seem to be the best, because sequence-converted String is not a String sequence, but Character:
$ swift
Welcome to Swift! Type :help for assistance.
1> Array("ABC")
$R0: [Character] = 3 values {
[0] = "A"
[1] = "B"
[2] = "C"
}
This below works for me:
let str = "ABC"
let arr = map(str) { s -> String in String(s) }
Reference for a global function map() is here: http://swifter.natecook.com/func/map/
There is also this useful function on String: components(separatedBy: String)
let string = "1;2;3"
let array = string.components(separatedBy: ";")
print(array) // returns ["1", "2", "3"]
Works well to deal with strings separated by a character like ";" or even "\n"
For Swift version 5.3 its easy as:
let string = "Hello world"
let characters = Array(string)
print(characters)
// ["H", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
Updated for Swift 4
Here are 3 ways.
//array of Characters
let charArr1 = [Character](myString)
//array of String.element
let charArr2 = Array(myString)
for char in myString {
//char is of type Character
}
In some cases, what people really want is a way to convert a string into an array of little strings with 1 character length each. Here is a super efficient way to do that:
//array of String
var strArr = myString.map { String($0)}
Swift 3
Here are 3 ways.
let charArr1 = [Character](myString.characters)
let charArr2 = Array(myString.characters)
for char in myString.characters {
//char is of type Character
}
In some cases, what people really want is a way to convert a string into an array of little strings with 1 character length each. Here is a super efficient way to do that:
var strArr = myString.characters.map { String($0)}
Or you can add an extension to String.
extension String {
func letterize() -> [Character] {
return Array(self.characters)
}
}
Then you can call it like this:
let charArr = "Cat".letterize()
An easy way to do this is to map the variable and return each Character as a String:
let someText = "hello"
let array = someText.map({ String($0) }) // [String]
The output should be ["h", "e", "l", "l", "o"].
for the function on String: components(separatedBy: String)
in Swift 5.1
have change to:
string.split(separator: "/")
Martin R answer is the best approach, and as he said, because String conforms the SquenceType protocol, you can also enumerate a string, getting each character on each iteration.
let characters = "Hello"
var charactersArray: [Character] = []
for (index, character) in enumerate(characters) {
//do something with the character at index
charactersArray.append(character)
}
println(charactersArray)
let string = "hell0"
let ar = Array(string.characters)
print(ar)
In Swift 4, as String is a collection of Character, you need to use map
let array1 = Array("hello") // Array<Character>
let array2 = Array("hello").map({ "\($0)" }) // Array<String>
let array3 = "hello".map(String.init) // Array<String>
You can also create an extension:
var strArray = "Hello, playground".Letterize()
extension String {
func Letterize() -> [String] {
return map(self) { String($0) }
}
}
func letterize() -> [Character] {
return Array(self.characters)
}
Suppose you have four text fields otpOneTxt, otpTwoTxt, otpThreeTxt, otpFourTxt and a string getOtp.
let getup = "5642"
let array = self.getOtp.map({ String($0) })
otpOneTxt.text = array[0] //5
otpTwoTxt.text = array[1] //6
otpThreeTxt.text = array[2] //4
otpFourTxt.text = array[3] //2
let str = "cdcd"
let characterArr = str.reduce(into: [Character]()) { result, letter in
result.append(letter)
}
print(characterArr)
//["c", "d", "c", "d"]