This question already has answers here:
How to sort array of strings by length in reverse/descending order in Swift?
(2 answers)
Closed last year.
Good day everyone I want to create a function that takes an array of strings and return an array, sorted from shortest to longest but I'm getting a terminated by signal 4 error. I'm using an online swift compiler on my windows laptop if that somehow matters.
here's the code I wrote:
var siliconvalley = ["Google", "Apple", "Microsoft"]
var elementamount: Int = siliconvalley.count
var newarray: [String] = [] //new array created to store the newly sorted array
var a = siliconvalley[0].count // this variable was created to count the letters of the first string in the array
var temporary: String = "" // this was created to store the largest string so that I can use it to append the new array
func longestelement () -> [String] {
repeat {
if siliconvalley[1].count > a {
print (siliconvalley[1])
temporary = siliconvalley[1]
siliconvalley.remove(at:1)
}
else if siliconvalley[2].count > a {
print (siliconvalley[2])
temporary = siliconvalley[2]
siliconvalley.remove(at:2)
}
else {
print (siliconvalley[0])
temporary = siliconvalley[0]
siliconvalley.remove(at:0)
}
newarray.append(temporary)
elementamount = elementamount - 1
} while elementamount > 0
return newarray
}
print (longestelement())
You know swift has built-in sorting? You can do:
siliconvalley.sorted(by: {$0.count < $1.count})
and then if you just want the longest use .last
here's the issue:
while elementamount > 0
Consider rechecking the code for possible illogical loop termination condition.
P.S: elementamount is always greater than 0.
Related
Hi I would like to store values of a 1D array into a 2D array.
My 1D array has 50 elements and I want to store it in a 5x10 array, but whenever I do that, it always gives me a "Index out of range" error
Any help would be appreciated thanks!
var info2d = [[String]]()
var dataArray = outputdata.components(separatedBy: ";")
for j in 0...10 {
for i in 0...5 {
info2d[i][j] = dataArray[(j)*5+i]
print(info2d[i][j])
}
}
Lots of error in your code.
info2d must be initialised with default values before using it by index
// initialising 2d array with empty string value
var info2d = [[String]](repeating: [String](repeating: "", count: 10), count: 5)
Secondly for loop with ... includes the last value too, use ..<
for j in 0..<10 {
//...
}
Thirdly (j)*5+i is incorrect too.
Better Read how to use arrays, collections and for loop in swift.
https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html
https://docs.swift.org/swift-book/LanguageGuide/CollectionTypes.html
I would make use of ArraySlice for this.
var arr2D = [[String]]()
for i in 0..<5 {
let start = i * 10
let end = start + 10
let slice = dataArray[start..<end] //Create an ArraySlice
arr2D.append(Array(slice)) //Create new Array from ArraySlice
}
Here is my code so far
var counter = 0
for i in 0...9 {
var val = NamePicker()
// array to find duplicates
var buttonValues = ["", "", "", "", "", "", "", "", "", ""] // array for button names
buttonValues.insert(val, at: counter)
print(buttonValues[counter])
counter += 1
}
This code is putting 10 string values into my array. What I would like to do is find a way to check each value in my array. for eample if my end result array is ["a","a","a","b","b","c","c","e","f","c"] I want to see if there is a triple of the same name(single and duplicates are fine). However if there is a triple I would like to change the 3rd value to another val from my NamePicker() function.
so with my array of
["a","a","a","b","b","c","c","e","f","c"]
there are 3 "a" and 3 "c", having two of the same is ok, i would like to change the 3rd to a new values and if the new value makes another triple it will change until there are no more triples.
so that array could possible have an end result of
["a","a","f","b","b","c","c","e","f","z"]
this is where the triples where changed.
Any help on how to do this efficiently?
Both options below asume that your NamePciker() function can generate at least 5 distinct values so there exists an array that satisfies your requirement.
Your requirement is better handled by not generating so many duplicates to begin with. If all you want is an array of names when each name cannot be repeated more than twice, try this:
var buttonValues = [String]()
var dict = [String: Int]()
while buttonValues.count < 10 {
let name = NamePicker()
let count = dict[name] ?? 0
guard count < 2 else { continue }
buttonValues.append(name)
dict[name] = count + 1
}
If you already have the array and want to correct it, do this:
var buttonValues = ["a","a","a","b","b","c","c","e","f","c"]
// Scan the array to tally how many times each name appears
var totalDict = [String: Int]()
buttonValues.forEach { totalDict[$0] = (totalDict[$0] ?? 0) + 1 }
// Now scan it again to update names that appear too many times
var runningDict = [String: Int]()
for (index, value) in buttonValues.enumerated() {
let count = runningDict[value] ?? 0
if count >= 2 {
while true {
let newValue = NamePicker()
let newTotal = (totalDict[newValue] ?? 0) + 1
if newTotal < 3 {
buttonValues[index] = newValue
totalDict[newValue] = newTotal
break
}
}
} else {
runningDict[value] = count + 1
}
}
Dictionary is the best way I think. Have the key be the character and the value be the count of that character. Your runtime will be O(n) since you only have to run through each input once. Here is an example:
let chars = ["a","a","a","b","b","c","c","e","f","c"]
var dict = [String: Int]()
for char in chars {
//If already in Dictionary, increase by one
if var count = dict[char] {
count += 1
dict[char] = count
} else {//else is not in the dictionary already, init with 1
dict[char] = 1
}
}
Output:
["b": 2, "e": 1, "a": 3, "f": 1, "c": 3]
Now I'm not sure how you want to replace the value that's the same character for a third time, but this is probably the best way to group the strings to determine which are over the limit.
Instead of inserting the wrong value and then checking if the values are correct, I would suggest to automatically create the correct array.
//array for button names
var buttonValues = Array<String>()
//tracks what value has been inserted how many times
var trackerDict = [String: Int]()
for i in 0...9 {
//we initialize a new variable that tells us if we found a valid value (if the value has not been inserted 2 times already)
var foundValidValue = false
while !foundValidValue{
var val = NamePicker()
//now we check if the value exists and if it is inserted less than 2 times
if let count = trackerDict[val] {
if count < 2 {
foundValidValue = true
}
}
//if we found the value, we can add it
if foundValidValue {
trackerDict[val] = (trackerDict[val] ?? 0) + 1
buttonValues.append(val)
}
//if we did not find it, we just run through the loop again
}
}
I added a dictionary because it is faster to keep track of the count in a dictionary than counting the number of occurrences in the array every time.
This is a follow up question to How to have 10 characters total and make sure at least one character from 4 different sets is used randomly
this is my code so far
let sets = ["ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz", "1234567890", "\"-/:;()$&#.,?!'[]{}#%^\\|~<>€£¥•.,"].map { Array($0.characters) }
var randoms = sets.map { $0.random }
while randoms.count < 10 {
randoms.append(sets.random.random)
}
var convertedElems = String()
let something = randoms.shuffled()
for key in something {
convertedElems = String(key)
}
uniqueRoomID.text = randoms.shuffled()
Im getting an error saying cannot convert [Element] to type "String"
So i tried a for loop but that only converts 1 at a time when its supposed to do all 10
my other question is i tried storing a character in a variable and then setting a text field.text equal to that variable and nothing happened
What am i doing wrong here
Your randoms.shuffled() is an array of Characters. You need to convert it back into a String.
Change this:
uniqueRoomID.text = randoms.shuffled()
to this:
uniqueRoomID.text = String(randoms.shuffled())
I'm working on a project which includes verifying the checksum of an Int input with the Damm Algorithm. I've managed to create a the operational table and my method for accessing the value in the table involves passing an interim value and a digit to pass in as the column value.
ex.
self.tableToUse[interim,checkSumArray[i]]
Unfortunately, I've run into a snag when I'm trying to pass the digits from my input into the the get/set method where I cannot find a way to convert the Characters into Ints.
func encode(number: Int) -> Int{
var checkSumArray = [Int]()
if number > 99999999 {
println("number is too large")
return 0
}
else if number < 0 {
println("invalid input")
return 0
}
else {
checkSumArray.append(number%(10))
checkSumArray.append((number%(100)-checkSumArray[0])/10)
checkSumArray.append((number%(1000)-checkSumArray[1])/100)
checkSumArray.append((number%(10000)-checkSumArray[2])/1000)
checkSumArray.append((number%(100000)-checkSumArray[3])/10000)
checkSumArray.append((number%(1000000)-checkSumArray[4])/100000)
checkSumArray.append((number%(10000000)-checkSumArray[5])/1000000)
checkSumArray.append((number%(100000000)-checkSumArray[6])/10000000)
checkSumArray = checkSumArray.reverse()
var interim: Int = 0
for i in 0..<checkSumArray.count{
interim = self.tableToUse[interim,checkSumArray[i]]
}
return interim
}
}
As you can see, I've had to resort to a really nasty way of dealing with this. It works, but it's very limited, inefficient, and just ugly to look at or maintain. I've looked at the option of using Characters instead of Ints in the Damm Table I've constructed and altering the get/set method to deal with those instead, but that's a lot of extra work and could introduce other issues. Any suggestions of alternative ways to handle this, or a way to convert Characters to Ints would be appreciated.
Thanks!
Based on How convert a *positive* number into an array of digits in Swift, you could do (the number has to be positive):
let checkSumArray = map(number.description) { String($0).toInt()! }
if let int = Int(String(Character("1"))) {
print(int)
}
You can also create a character extension as follow:
extension Character {
var integerValue: Int? {
return Int(String(self))
}
}
Testing
Character("1").integerValue // 1
Character("2").integerValue // 2
Character("3").integerValue // 3
Character("4").integerValue // 4
Character("5").integerValue // 5
Character("6").integerValue // 6
Character("7").integerValue // 7
Character("8").integerValue // 8
Character("9").integerValue // 9
Character("0").integerValue // 0
Character("a").integerValue // nil
Array("9876").first!.integerValue // 9
Array("9876")[1].integerValue // 8
Array("9876")[2].integerValue // 7
Array("9876").last!.integerValue // 6
edit/update Swift 5
Swift 5 adds many new properties to the Character and one of them fits exactly to this purpose. It is called wholeNumberValue
Character("1").wholeNumberValue // 1
Character("2").wholeNumberValue // 2
Character("3").wholeNumberValue // 3
Character("4").wholeNumberValue // 4
Character("④").wholeNumberValue // 4
Character("5").wholeNumberValue // 5
Character("6").wholeNumberValue // 6
Character("7").wholeNumberValue // 7
Character("8").wholeNumberValue // 8
Character("9").wholeNumberValue // 9
Character("0").wholeNumberValue // 0
Character("万").wholeNumberValue // 10_000
Character("a").wholeNumberValue // nil
There is no need to work with characters, but your code to create an
array with the decimal digits of the input number can be greatly
simplified:
var checkSumArray = [Int]()
var tmp = number
while tmp > 0 {
checkSumArray.append(tmp % 10)
tmp /= 10
}
checkSumArray = checkSumArray.reverse()
is there a possibility to get an object from an array with an specific property? Or do i need to loop trough all objects in my array and check if an property is the specific i was looking for?
edit: Thanks for given me into the correct direction, but i have a problem to convert this.
// edit again: A ok, and if there is only one specific result? Is this also a possible method do to that?
let imageUUID = sender.imageUUID
let questionImageObjects = self.formImages[currentSelectedQuestion.qIndex] as [Images]!
// this is working
//var imageObject:Images!
/*
for (index, image) in enumerate(questionImageObjects) {
if(image.imageUUID == imageUUID) {
imageObject = image
}
}
*/
// this is not working - NSArray is not a subtype of Images- so what if there is only 1 possible result?
var imageObject = questionImageObjects.filter( { return $0.imageUUID == imageUUID } )
// this is not working - NSArray is not a subtype of Images- so what if there is only 1 possible result?
You have no way to prove at compile-time that there is only one possible result on an array. What you're actually asking for is the first matching result. The easiest (though not the fastest) is to just take the first element of the result of filter:
let imageObject = questionImageObjects.filter{ $0.imageUUID == imageUUID }.first
imageObject will now be an optional of course, since it's possible that nothing matches.
If searching the whole array is time consuming, of course you can easily create a firstMatching function that will return the (optional) first element matching the closure, but for short arrays this is fine and simple.
As charles notes, in Swift 3 this is built in:
questionImageObjects.first(where: { $0.imageUUID == imageUUID })
Edit 2016-05-05: Swift 3 will include first(where:).
In Swift 2, you can use indexOf to find the index of the first array element that matches a predicate.
let index = questionImageObjects.indexOf({$0.imageUUID == imageUUID})
This is bit faster compared to filter since it will stop after the first match. (Alternatively, you could use a lazy sequence.)
However, it's a bit annoying that you can only get the index and not the object itself. I use the following extension for convenience:
extension CollectionType {
func find(#noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Self.Generator.Element? {
return try indexOf(predicate).map({self[$0]})
}
}
Then the following works:
questionImageObjects.find({$0.imageUUID == imageUUID})
Yes, you can use the filter method which takes a closure where you can set your logical expression.
Example:
struct User {
var firstName: String?
var lastName: String?
}
let users = [User(firstName: "John", lastName: "Doe"), User(firstName: "Bill", lastName: "Clinton"), User(firstName: "John", lastName: "Travolta")];
let johns = users.filter( { return $0.firstName == "John" } )
Note that filter returns an array containing all items satisfying the logical expression.
More info in the Library Reference
Here is a working example in Swift 5
class Point{
var x:Int
var y:Int
init(x:Int, y:Int){
self.x = x
self.y = y
}
}
var p1 = Point(x:1, y:2)
var p2 = Point(x:2, y:3)
var p3 = Point(x:1, y:4)
var points = [p1, p2, p3]
// Find the first object with given property
// In this case, firstMatchingPoint becomes p1
let firstMatchingPoint = points.first{$0.x == 1}
// Find all objects with given property
// In this case, allMatchingPoints becomes [p1, p3]
let allMatchingPoints = points.filter{$0.x == 1}
Reference:
Trailing Closure
Here is other way to fetch particular object by using object property to search an object in array.
if arrayTicketsListing.contains({ $0.status_id == "2" }) {
let ticketStatusObj: TicketsStatusList = arrayTicketsListing[arrayTicketsListing.indexOf({ $0.status_id == "2" })!]
print(ticketStatusObj.status_name)
}
Whereas, my arrayTicketsListing is [TicketsStatusList] contains objects of TicketsStatusList class.
// TicketsStatusList class
class TicketsStatusList {
internal var status_id: String
internal var status_name: String
init(){
status_id = ""
status_name = ""
}
}