Swift 3 : Remove value in Array with Unknown index - arrays

I want to implement a multiple click in my Shinobi DataGrid. I have a grid which have array
( ["1", "32", and more] )
If I click the grid I put it into new Array self.arrayNr.append(currNr).
But I want to check and remove if currNr is already exist in arrayNr it is will be remove from the arrayNr.
I'm new and using Swift 3. I read some question regarding with my question like this and this but it's not working. I think the Swift 2 is simpler than Swift 3 in handling for String. Any sugesstion or answer will help for me?

You can use index(of to check if the currNrexists in your array. (The class must conform to the Equatable protocol)
var arrayNr = ["1", "32", "100"]
let currNr = "32"
// Check to remove the existing element
if let index = arrayNr.index(of: currNr) {
arrayNr.remove(at: index)
}
arrayNr.append(currNr)

Say you have an array of string, namely type [String]. Now you want to remove a string if it exists. So you simply need to filter the array by this one line of code
stringArray= stringArray.filter(){$0 != "theValueThatYouDontWant"}
For example, you have array like this and you want to remove "1"
let array = ["1", "32"]
Simply call
array = array.filter(){$0 != "1"}

Long Solution
sampleArray iterates over itself and removes the value you are looking for if it exists before exiting the loop.
var sampleArray = ["Hello", "World", "1", "Again", "5"]
let valueToCheck = "World"
for (index, value) in sampleArray.enumerated() {
if value == valueToCheck && sampleArray.contains(valueToCheck) {
sampleArray.remove(at: index)
break
}
}
print(sampleArray) // Returns ["Hello", "1", "Again", "5"]
Short Solution
sampleArray returns an array of all values that are not equal to the value you are checking.
var sampleArray = ["Hello", "World", "1", "Again", "5"]
let valueToCheck = "World"
sampleArray = sampleArray.filter { $0 != valueToCheck }
print(sampleArray) // Returns ["Hello", "1", "Again", "5"]

Related

Swift: Filter string by using start with

I have an array as follows:
let array = ["sam", "andrew", "character"]
And I want to get every element in the array that starts with a character I type
My problem is when i type "a" the output is "sam", "andrew", and "character".
I want to get the output to only be "andrew". (The string must start from left to right when searching)
You need to filter your array using hasPrefix
var names = ["sam", "andrew", "character"]
var searchString = "a"
let filteredNames = names.filter({ $0.hasPrefix(searchString) })
print(filteredNames)
You must use string.hasPrefix(string)
You can try to use this in Swift 5:
let filteredNames = names.filter{$0.range(of: searchText, options: [.caseInsensitive, .anchored]) != nil}

How to map an array of integers as keys to dictionary values

If I have the following array and I want to create a string array containing the door prizes by mapping the mysteryDoors array as keys for the dictionary, and get the corresponding values into a new array.
Thus I would get a string array of ["Gift Card", "Car", "Vacation"] how can I do that?
let mysteryDoors = [3,1,2]
let doorPrizes = [
1:"Car", 2: "Vacation", 3: "Gift card"]
You can map() each array element to the corresponding value in
the dictionary. If it is guaranteed that all array elements are
present as keys in the dictionary then you can do:
let mysteryDoors = [3, 1, 2]
let doorPrizes = [ 1:"Car", 2: "Vacation", 3: "Gift card"]
let prizes = mysteryDoors.map { doorPrizes[$0]! }
print(prizes) // ["Gift card", "Car", "Vacation"]
To avoid a runtime crash if a key is not present, use
let prizes = mysteryDoors.flatMap { doorPrizes[$0] }
to ignore unknown keys, or
let prizes = mysteryDoors.map { doorPrizes[$0] ?? "" }
to map unknown keys to a default string.
If you have to use map, then it would look something like the following:
let array = mysteryDoors.map { doorPrizes[$0] }
After re-reading the Apple Doc example code and changing it to what I need. I believe this is it (Almost). Unfortunately it is now in string format with new lines...
let myPrizes = doorPrizes.map { (number) -> String in
var output = ""
output = mysteryDoors[number]!
return output;
}

Not able to add values to a dictionary

I have a dictionary -> var dictionary = [String : [String]]() and I want to append string values in the array of the dictionary. This is how I'm doing it
for (key, value) in dictionary {
dictionary.updateValue(value.append(nameText),forKey: "name")
}
Here, nameText is a string, I'm getting an error saying,
Cannot use mutating member on immutable value: 'value' is a 'let' constant.
What am I doing wrong? Help would be much appreciated.
Your first issue is that value is a let constant within your loop body. You must declare it as var in order to mutate it.
Your second issue is that you're trying to use value.append(nameText) as the value to set for the key. However, append() mutates the array in place, and returns Void.
Thirdly, don't use updateValue(forKey:). There's really no point. Use subscripting instead.
var dictionary = [
"a" : ["a"],
"b" : ["b", "b"],
"c" : ["c", "c", "c"],
]
let nameText = "foo"
for (key, var value) in dictionary {
value.append(nameText)
dictionary["name"] = value
}
Now, this gets your code to compile, but I'm highly skeptical this is really what you want to do. You'll be overwriting the value for the "name" key on every iteration, meaning only the last iteration's value will persist. Furthermore, because Dictionary doesn't have a defined ordering, this code has indeterminate behaviour. What are you actually trying to do?
Try this:
for (key, value) in dictionary {
dictionary.updateValue(value + [nameText], forKey: key)
}
Think about it for a second; value.append(nameText) is an action. It returns Void (the type for ... nothing!).
You want to update the value to something upon which an action has been performed.
Instead of manually making a temporary copy, modifying that, and then using it to update the value for some key, you can simply use subscripts and extensions:
What you want is:
extension Dictionary
{
public subscript(forceUnwrapping key: Key) -> Value
{
get
{
return self[key]!
}
set
{
self[key] = newValue
}
}
}
So, for a dictionary named dictionary:
for key in dictionary.keys
{
dictionary[forceUnwrapping: key].append(nameText)
}
Specifically, dictionary[forceUnwrapping: key].append(nameText).
/* example setup */
var dictionary: [String: [String]] = ["foo": [], "bar": []]
let nameText = "foobar"
/* append the value of the 'nameText' immutable to each inner array */
dictionary.keys.forEach { dictionary[$0]?.append(nameText) }
/* ok! */
print(dictionary) // ["bar": ["foobar"], "foo": ["foobar"]]
As described in the following Q&A, however
Dictionary in Swift with Mutable Array as value is performing very slow? How to optimize or construct properly?
..., it is good to be aware of the overhead of mutating "in place", especially if working performance tight applications. Taking the advice from the answer in the linked thread above, an alternative, more sensible and less copy-wasteful approach would be e.g.:
var dictionary: [String: [String]] = ["foo": [], "bar": []]
let nameText = "foobar"
dictionary.keys.forEach {
var arr = dictionary.removeValue(forKey: $0) ?? []
arr.append(nameText)
dictionary[$0] = arr
}
print(dictionary) // ["bar": ["foobar"], "foo": ["foobar"]]

Swift Set to Array

An NSSet can be converted to Array using set.allObjects() but there is no such method in the new Set (introduced with Swift 1.2). It can still be done by converting Swift Set to NSSet and use the allObjects() method but that is not optimal.
You can create an array with all elements from a given Swift
Set simply with
let array = Array(someSet)
This works because Set conforms to the SequenceType protocol
and an Array can be initialized with a sequence. Example:
let mySet = Set(["a", "b", "a"]) // Set<String>
let myArray = Array(mySet) // Array<String>
print(myArray) // [b, a]
In the simplest case, with Swift 3, you can use Array's init(_:) initializer to get an Array from a Set. init(_:) has the following declaration:
init<S>(_ s: S) where S : Sequence, Element == S.Iterator.Element
Creates an array containing the elements of a sequence.
Usage:
let stringSet = Set(arrayLiteral: "car", "boat", "car", "bike", "toy")
let stringArray = Array(stringSet)
print(stringArray)
// may print ["toy", "car", "bike", "boat"]
However, if you also want to perform some operations on each element of your Set while transforming it into an Array, you can use map, flatMap, sort, filter and other functional methods provided by Collection protocol:
let stringSet = Set(["car", "boat", "bike", "toy"])
let stringArray = stringSet.sorted()
print(stringArray)
// will print ["bike", "boat", "car", "toy"]
let stringSet = Set(arrayLiteral: "car", "boat", "car", "bike", "toy")
let stringArray = stringSet.filter { $0.characters.first != "b" }
print(stringArray)
// may print ["car", "toy"]
let intSet = Set([1, 3, 5, 2])
let stringArray = intSet.flatMap { String($0) }
print(stringArray)
// may print ["5", "2", "3", "1"]
let intSet = Set([1, 3, 5, 2])
// alternative to `let intArray = Array(intSet)`
let intArray = intSet.map { $0 }
print(intArray)
// may print [5, 2, 3, 1]
I created a simple extension that gives you an unsorted Array as a property of Set in Swift 4.0.
extension Set {
var array: [Element] {
return Array(self)
}
}
If you want a sorted array, you can either add an additional computed property, or modify the existing one to suit your needs.
To use this, just call
let array = set.array
ADDITION :
Swift has no DEFINED ORDER for Set and Dictionary.For that reason you should use sorted() method to prevent from getting unexpected results such as your array can be like ["a","b"] or ["b","a"] and you do not want this.
TO FIX THIS:
FOR SETS
var example:Set = ["a","b","c"]
let makeExampleArray = [example.sorted()]
makeExampleArray
Result: ["a","b","c"]
Without sorted()
It can be:
["a","b","c"] or ["b","c","a",] or ["c","a","b"] or ["a","c","b"] or ["b","a","c"] or ["c","b","a"]
simple math : 3! = 6
The current answer for Swift 2.x and higher (from the Swift Programming Language guide on Collection Types) seems to be to either iterate over the Set entries like so:
for item in myItemSet {
...
}
Or, to use the "sorted" method:
let itemsArray = myItemSet.sorted()
It seems the Swift designers did not like allObjects as an access mechanism because Sets aren't really ordered, so they wanted to make sure you didn't get out an array without an explicit ordering applied.
If you don't want the overhead of sorting and don't care about the order, I usually use the map or flatMap methods which should be a bit quicker to extract an array:
let itemsArray = myItemSet.map { $0 }
Which will build an array of the type the Set holds, if you need it to be an array of a specific type (say, entitles from a set of managed object relations that are not declared as a typed set) you can do something like:
var itemsArray : [MyObjectType] = []
if let typedSet = myItemSet as? Set<MyObjectType> {
itemsArray = typedSet.map { $0 }
}
call this method and pass your set
func getArrayFromSet(set:NSSet)-> NSArray {
return set.map ({ String($0) })
}
Like This :
var letters:Set = Set<String>(arrayLiteral: "test","test") // your set
print(self.getArrayFromSet(letters))

Sort array in Swift Ascending with empty items

In Xcode (Swift) I have an array that is initialized to 100 empty items:
var persons = [String](count:100, repeatedValue: "")
With some functions I add content to the places in the array, starting at 0.
So for example my array is at some given moment:
["Bert", "Daniel", "Claire", "Aaron", "", "", ... ""]
With the dots representing the rest of the empty items. I use this function for sorting my array alphabetically:
persons = persons.sorted {$0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
This gives me an array back like this:
["", "", ... , "Aaron", "Bert", "Claire", "Daniel"]
What I want is to sort my array alphabetically but not with the empty items at the front. I need to get an array back like:
["Aaron", "Bert", "Claire", "Daniel", "", "", ... , ""]
For my part, I do not want an array with empty items but I found I couldn't add a value to my array if I did not declare like a 100 items (the array won't be filled to a 100 items, that's for sure).
Can anyone help me out?
As #Antonio said, it looks like you need a descending order set of strings. Besides the Dictionary method in #Antonio's answer (which works great), you can also use NSMutableSet (bridged from Objective-C):
let personSet = NSMutableSet()
personSet.addObject("Aaron")
personSet.addObject("Daniel")
personSet.addObject("Claire")
personSet.addObject("Aaron")
personSet.addObject("Bert")
personSet.addObject("Bert")
personSet.addObject("Joe")
personSet.removeObject("Joe") // You can remove too of course
Which creates the set:
{(
Claire,
Aaron,
Daniel,
Bert
)}
Then, when you want the people as an Array, you can use the allObjects cast to a [String]:
personSet.allObjects as [String]
And you can sort it just like you're currently doing:
let people = (personSet.allObjects as [String]).sort {$0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
Which makes people:
[Aaron, Bert, Claire, Daniel]
For those wondering how to sort the Array as originally stated in the question (Ascending but with empty strings at the end), that can be done with a little bit of custom logic in the sort function:
var persons = ["Bert", "Daniel", "Claire", "Aaron", "", "", ""]
persons.sort { (a, b) -> Bool in
if a.isEmpty {
return false
} else if b.isEmpty {
return true
} else {
return a.localizedCaseInsensitiveCompare(b) == .OrderedAscending
}
}
Result:
["Aaron", "Bert", "Claire", "Daniel", "", "", ""]
Reading comments in your question and other answers, I realize that you need a ordered set, containing unique values. There's no built in data structure in swift for that, but it can be easily be done by using a dictionary: simply use the string value as dictionary key, and a boolean as dictionary value - this ensures that keys are unique:
var persons = [String : Bool]()
persons["Bert"] = true
persons["Daniel"] = true
persons["Clair"] = true
persons["Clair"] = true
persons["Aaron"] = true
persons["Daniel"] = true
persons["Clair"] = true
You can quickly verify that with the above code the dictionary contains 4 elements only.
Next, obtain a copy of the dictionary keys (as an array):
var values = persons.keys.array
and sort it:
values.sort { $0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
Alternatively, if you want to stick with the fixed sized array, you can remove the empty items before sorting:
persons = persons
.filter( { $0.isEmpty == false } )
.sorted {$0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
I think you are confused about arrays. Swift arrays are not statically allocated structures which must be allocated and filled to maximum design capacity. Below is a crude example of how you can accomplish most of what you are expressing here. However, I really think that a dictionary is better suited to your needs.
var persons = [String]()
var inputData = ["Bert", "Daniel", "Bert", "Claire", "Aaron"]
for item in inputData {
var found = false
for existing in persons {
if existing == item {
found = true
break
}
}
if (!found) {
persons.append(item)
}
}
persons.sort{$0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending }
println(persons)

Resources