String Sorting Based on Last Character in Swift - arrays

I want to sort my string array based on last character. Here is my string array:
["c_572A267C-DAC8-487D-B1AF-719FE8E3A6AB_FF6E00_2",
"b_69E21DC6-431C-4373-B4F1-90BF7FB5462B_FFC000_1"]
Now I want to sort this array based on last value that is after last underscore(_).
Is it possible ?
Thanks

sorted can provide a custom sort condition for example (assuming that all strings are not empty)
let array = ["c_572A267C-DAC8-487D-B1AF-719FE8E3A6AB_FF6E00_2", "b_69E21DC6-431C-4373-B4F1-90BF7FB5462B_FFC000_1"]
let sortedArray = array.sorted { $0.substring(from: $0.index(before: $0.endIndex)) < $1.substring(from: $1.index(before: $1.endIndex)) }
Swift 3+ the syntax is much more convenient
let array = ["c_572A267C-DAC8-487D-B1AF-719FE8E3A6AB_FF6E00_2", "b_69E21DC6-431C-4373-B4F1-90BF7FB5462B_FFC000_1"]
let sortedArray = array.sorted { $0.suffix(1) < $1.suffix(1) }

No doubt it is. By using sorted(by:), you could do it like this:
let myArray = ["c_572A267C-DAC8-487D-B1AF-719FE8E3A6AB_FF6E00_2",
"b_69E21DC6-431C-4373-B4F1-90BF7FB5462B_FFC000_1"]
let sortedArray = myArray.sorted {
guard let str1LastChar = $0.characters.last, let str2LastChar = $1.characters.last else {
return false
}
return str1LastChar < str2LastChar
}
print(sortedArray)
Note that if myArray contains any empty string ("") the sort should be as is.

One more answer with Higher Order Function:
Reverse Each word in an Array
Then, Sort
let arr = ["c_572A267C-DAC8-487D-B1AF-719FE8E3A6AB_FF6E00_2",
"b_69E21DC6-431C-4373-B4F1-90BF7FB5462B_FFC000_1"]
One Line:
let returnValue = arr.map({String($0.reversed())}).sorted().map({String($0.reversed())})
Multi Line:
let reverseEachWordsArr = arr.map { value in
return String(value.reversed())
}
let finalCharSortArr = reverseEachWordsArr.sorted().map { word in
return String(word.reversed())
}
print(finalCharSortArr)
OUTPUT:
["b_69E21DC6-431C-4373-B4F1-90BF7FB5462B_FFC000_1",
"c_572A267C-DAC8-487D-B1AF-719FE8E3A6AB_FF6E00_2"]

Related

Swift: sort an array of strings...of more or less numbers

I have an array of strings, examples are as follows:
"0.125-0.25"
"1-2"
"50-100"
"100-200"
The result of sorting these is:
"0.125-0.25"
"1-2"
"100-200"
"50-100"
And if I append("1000-2000") to the array and then sort it will be:
"0.125-0.25"
"1-2"
"100-200"
"1000-2000"
"50-100"
But what I want is:
"0.125-0.25"
"1-2"
"50-100"
"100-200"
"1000-2000"
It's definitely an edge case, but I have been having luck on my own. Thanks everyone.
A working but not very efficient solution is to extract the first Double value in the string ranges and sort by them. It's very inefficient because in each call of the closure both Double values have to be recreated.
var array = ["1-2", "50-100", "0.125-0.25", "100-200"]
array.append("1000-2000")
let sortedArray = array.sorted { (str1, str2) -> Bool in
func firstDouble(of string: String) -> Double { return Double(string.components(separatedBy: "-").first!)! }
return firstDouble(of: str1) < firstDouble(of: str2)
}
print(sortedArray)
A more efficient solution is to map the array (once) to its first Double value, then zip both arrays, sort the combined array by the Double array and map the result back to the string-range array.
var array = ["1-2", "50-100", "0.125-0.25", "100-200"]
array.append("1000-2000")
let firstDoubleArray = array.map{Double($0.components(separatedBy: "-").first!)!}
let sortedArray = zip(array, firstDoubleArray).sorted {$0.1 < $1.1}.map{$0.0}
print(sortedArray)
What it appears you're sorting is ranges of Doubles, so the problem can be clarified by creating an intermediate object…
struct DoubleRange: Comparable {
let start: Double
let end: Double
init(string: String) {
let components = string.split(separator: "-")
start = Double(components[0])! // Be careful with `!` here, I'm assuming the format is always correct
end = Double(components[1])!
}
var stringValue: String {
return "\(start)-\(end)"
}
static func < (lhs: DoubleRange, rhs: DoubleRange) -> Bool {
return lhs.start < rhs.start
}
}
Then sorting is simple…
var array = ["1-2", "50-100", "0.125-0.25", "100-200"]
array.append("1000-2000")
array.map(DoubleRange.init).sorted().map{$0.stringValue}
// ["0.125-0.25", "1.0-2.0", "50.0-100.0", "100.0-200.0", "1000.0-2000.0"]
And if you always want to convert back to the string value, you could add…
extension Array where Element == String {
func sortedDoubleRange() -> [String] {
return array.map(DoubleRange.init).sorted().map{$0.stringValue}
}
}
array.sortedDoubleRange()
Be careful with this though… it will crash if any of strings are formatted incorrectly.

How to convert String array to Int array in Kotlin?

Kotlin has many shorthands and interesting features. So, I wonder if there is some fast and short way of converting array of string to array of integers. Similar to this code in Python:
results = [int(i) for i in results]
You can use .map { ... } with .toInt() or .toIntOrNull():
val result = strings.map { it.toInt() }
Only the result is not an array but a list. It is preferable to use lists over arrays in non-performance-critical code, see the differences.
If you need an array, add .toTypedArray() or .toIntArray().
I'd use something simple like
val strings = arrayOf("1", "2", "3")
val ints = ints.map { it.toInt() }.toTypedArray()
Alternatively, if you're into extensions:
fun Array<String>.asInts() = this.map { it.toInt() }.toTypedArray()
strings.asInts()
If you are trying to convert a List structure that implements RandomAccess (like ArrayList, or Array), you can use this version for better performance:
IntArray(strings.size) { strings[it].toInt() }
This version is compiled to a basic for loop and int[]:
int size = strings.size();
int[] result = new int[size];
int index = 0;
for(int newLength = result.length; index < newLength; ++index) {
String numberRaw = strings.get(index);
int parsedNumber = Integer.parseInt(numberRaw);
result[index] = parsedNumber;
}
If you use Array.map as other answers suggest, you get back a List, not an Array. If you want to map an array strings to another array results, you can do it directly like this:
val results = Array(strings.size) { strings[it].toInt() }
This is more efficient than first mapping to a List and then copying the elements over to an Array by calling .toTypedArray().
Consider the input like this "" (empty string)
It would be better to do the filtering first. And it is true the return value is list but not array.
If you need an array, add .toTypedArray() or .toIntArray().
fun stringToIntList(data: String): List<Int> =
data.split(",").filter { it.toIntOrNull() != null }
.map { it.toInt() }
val result = "[1, 2, 3, 4, 5]".removeSurrounding("[","]").replace(" ","").split(",").map { it.toInt() }
Found following simplest
strings.chars().toArray()

String into array in Swift 3

I am trying to transform a string of the following format into an array (...of arrays, of floats!) in Swift 3:
"[173.0, 180.5],[173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
so that the output would be an array in this format:
[[173.0, 180.5, 173.0, 180.0],[174.0, 180.5, 174.0, 183.0]]
I am really new to Swift and struggling to find any String functions that will allow me to convert the data in this way. Any pointers on how I can do it would be awesome - thanks!
As Martin said, you first want to first convert this from a string to an array. In Swift 3:
let string = "[173.0, 180.5],[173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
let jsonString = "[" + string + "]"
guard let data = jsonString.data(using: .utf8),
let json = try? JSONSerialization.jsonObject(with: data),
let numberPairs = json as? [[Double]] else {
fatalError("string was not well-formed: \(string)")
}
You then want to combine these pairs of numbers together:
var combinedNumbers = [[Double]]()
var current: [Double]?
for numberPair in numberPairs {
if current != nil {
combinedNumbers.append(current! + numberPair)
current = nil
} else {
current = numberPair
}
}
// use `combinedNumbers` here
Clearly, you should use better variable names (perhaps something that suggests what these sets of numbers are), but hopefully this illustrates the idea.
Swift 4
You can use Decodable:
let str = "[173.0, 180.5],[173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
let json = "[\(str)]".data(using: .utf8)!
let numbers = try JSONDecoder().decode([[Double]].self, from: json).flatMap { $0 }
let result = stride(from: 0, to: numbers.count, by: 4).map { startIndex -> [Double] in
let endIndex = min(startIndex + 4, numbers.count)
return Array(numbers[startIndex..<endIndex])
}
Swift 3
One option is to use the old-school NSScanner to extract the numbers from the string to a flat array, then build a 2 dimensional array off that:
let str = "[173.0, 180.5],[173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
let scanner = Scanner(string: str)
scanner.charactersToBeSkipped = CharacterSet(charactersIn: "[], ")
// Build the flat array
var numbers = [Double]()
while !scanner.isAtEnd {
var d = 0.0
if scanner.scanDouble(&d) {
numbers.append(d)
}
}
// Now the 2 dimensional array
let result = stride(from: 0, to: numbers.count, by: 4).map { startIndex -> [Double] in
let endIndex = min(startIndex + 4, numbers.count)
return Array(numbers[startIndex..<endIndex])
}
One option to convert the data types would be to develop a simple algorithm that will iterate through the string and analyze elements and square bracket delimiters, returning the appropriate conversion.
Below is the skeleton of what the fundamental components of such a function could look like.
Included are some basic aspects of the conversion from string to array.
var str = "[173.0, 180.5], [173.0, 180.0],[174.0, 180.5],[174.0, 183.0]"
// Cast returns array ["[","1","7","3",".","0",",".......]
let array = Array(str.characters)
// Iterate through array
for char in array {
if char == "[" || char == "]" {
// Deal with array delimiters appropriately
}
...
}
It might help to check out this similar problem.
NOTE: As Martin R mentioned, JSON interpretation may be a good method as well.

Sort an array of dictionary (swift)

let unsorted = [{Name:Amy,age:20},{Name:Bill,age:20}]
let sortedDict = sorted(unsorted){a,b in return a.Name < b.Name}
How can I sort the unsorted array according to the Name key? Above code seems doesn't work.
Your sorting syntax works (almost) if you are using a custom struct rather than a dictionary
struct Person {
let name : String
let age : Int
}
let unsortedPeople = [Person(name:"Bill", age:20), Person(name:"Amy", age:20)]
Now you can use the sorted function
let sortedDict = unsortedPeople.sorted{ $0.name < $1.name }
Your dictionary in your question is wrong, so I am assuming you have a dictionary like
let unsorted = ["Amy": Amy, "Dan": Dan, "Ben": Ben]
If so, you can sort by
let sorted = unsorted.sort { $0.0 < $1.0 }

Swift Convert A String-As-An-Array, To An Array Of Strings

I have a string:
"["word1","word2"]"
And I want a simple way to convert it to an actual [String].
All the other questions I could dig up on there were about converting int strings to arrays.
I tried doing
Array(arrayLiteral: "["word1","word2"]")
But I get
["[\"word1\",\"word2\"]"]
Manually cleaning up the edges and removing the slashes seems like I'm doing something very wrong.
I'm curious if there's a simple way to convert a an array of strings as a string into an array of strings.
i.e. Convert "["word1","word2"]" to ["word1","word2"]
Solution (Thanks to #Eric D)
let data = stringArrayString.dataUsingEncoding(NSUTF8StringEncoding)
var stringsArray:[String]!
do
{
stringsArray = try NSJSONSerialization.JSONObjectWithData(data!, options: []) as? [String]
} catch
{
print()
}
print("Array is \(stringsArray)")
Encode your "string array" to data, then decode this data as JSON to a Swift Array.
Like this, for example:
let source = "[\"word1\",\"word2\"]"
guard let data = source.dataUsingEncoding(NSUTF8StringEncoding),
arrayOfStrings = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String] else {
fatalError()
}
print(arrayOfStrings) // ["word1", "word2"]
print(arrayOfStrings[1]) // "word2"
Agree with comments above, I'd probably use a JSON parser. Failing that (or if you can't for some reason), I do not know of any built-in way; you'd have to do it manually. I'd do something like:
extension String {
func stringByTrimmingFirstAndLast() -> String {
let startIndex = self.startIndex.successor()
let endIndex = self.endIndex.predecessor()
return self.substringWithRange( startIndex..<endIndex )
}
}
let str = "[\"word1\",\"word2\"]"
let array = str
.stringByTrimmingFirstAndLast()
.componentsSeparatedByString(",")
.map { string in
return string.stringByTrimmingFirstAndLast()
}

Resources