Can somebody give a snippet of append if not exists method in swift array?
You can extend RangeReplaceableCollection
, constrain its elements to Equatable
and declare your method as mutating. If you want to return Bool in case the appends succeeds you can also make the result discardable. Your extension should look like this:
extension RangeReplaceableCollection where Element: Equatable {
@discardableResult
mutating func appendIfNotContains(_ element: Element) -> (appended: Bool, memberAfterAppend: Element) {
if let index = firstIndex(of: element) {
return (false, self[index])
} else {
append(element)
return (true, element)
}
}
}
Simple way to replace an item in an array if it exists, append it if it doesn't
Given your use case, in which you're always checking $0.<prop> == newthing.<prop>
, you can lift this a little more by adding:
mutating func replaceOrAppend<Value>(_ item: Element,
firstMatchingKeyPath keyPath: KeyPath<Element, Value>)
where Value: Equatable
{
let itemValue = item[keyPath: keyPath]
replaceOrAppend(item, whereFirstIndex: { $0[keyPath: keyPath] == itemValue })
}
You can then use it like:
struct Student {
let id: Int
let name: String
}
let alice0 = Student(id: 0, name: "alice")
let alice1 = Student(id: 1, name: "alice")
let bob = Student(id: 0, name: "bob")
var array = [alice0]
array.replaceOrAppend(alice1, firstMatchingKeyPath: \.name) // [alice1]
array.replaceOrAppend(bob, firstMatchingKeyPath: \.name) // [alice1, bob]
And of course if you do this a lot, you can keep lifting and lifting.
protocol Identifiable {
var id: Int { get }
}
extension Student: Identifiable {}
extension Array where Element: Identifiable {
mutating func replaceOrAppendFirstMatchingID(_ item: Element)
{
replaceOrAppend(item, firstMatchingKeyPath: \.id)
}
}
array.replaceOrAppendFirstMatchingID(alice0) // [alice1, alice0]
how to prevent arraylist from adding the same string twice?
Make sure the string isn't already in the array before appending, like this:
@IBAction func add(_ sender: Any) {
if !myArray.contains(name) {
myArray.append(name)
}
}
How to validate array value already exist or not
You can use contains(where:)
to check if the array contains the element by comparing the unique properties in the class.
if !items.contains(where: {$0.url == fileUrl}) {
items.append(yourItem)
}
How to check if an element is in an array
Swift 2, 3, 4, 5:
let elements = [1, 2, 3, 4, 5]
if elements.contains(5) {
print("yes")
}
contains()
is a protocol extension method of SequenceType
(for sequences of Equatable
elements) and not a global method as in
earlier releases.
Remarks:
- This
contains()
method requires that the sequence elements
adopt theEquatable
protocol, compare e.g. Andrews's answer. - If the sequence elements are instances of a
NSObject
subclass
then you have to overrideisEqual:
, see NSObject subclass in Swift: hash vs hashValue, isEqual vs ==. - There is another – more general –
contains()
method which does not require the elements to be equatable and takes a predicate as an
argument, see e.g. Shorthand to test if an object exists in an array for Swift?.
Swift older versions:
let elements = [1,2,3,4,5]
if contains(elements, 5) {
println("yes")
}
Method signature to take the same array in array extension
Just simply pass parameter of type Array
extension Array {
func doSomethingWithAnotherArray(arr: Array) {
... // do something
}
}
[Int].doSomethingWithAnotherArray(arr: [Int]) // works
[Int].doSomethingWithAnotherArray(arr: [String]) // doesn't work
Avoid duplicates in Swift array
If you want to avoid duplicates why don't you use a Set anyway (Translation
must conform to Hashable
)?
var set = Set<Translation>()
However if you want to keep the array a more efficient way is to add an add
method which filters the duplicates, Translation
must conform to Equatable
func add(object: Translation) {
if !array.contains(object) {
array.append(object)
delegate?.newItemAdded()
}
}
Making a Set
from the Array
and then convert it back to Array
is unnecessarily expensive.
How to append elements into a dictionary in Swift?
You're using NSDictionary
. Unless you explicitly need it to be that type for some reason, I recommend using a Swift dictionary.
You can pass a Swift dictionary to any function expecting NSDictionary
without any extra work, because Dictionary<>
and NSDictionary
seamlessly bridge to each other. The advantage of the native Swift way is that the dictionary uses generic types, so if you define it with Int
as the key and String
as the value, you cannot mistakenly use keys and values of different types. (The compiler checks the types on your behalf.)
Based on what I see in your code, your dictionary uses Int
as the key and String
as the value. To create an instance and add an item at a later time you can use this code:
var dict = [1: "abc", 2: "cde"] // dict is of type Dictionary<Int, String>
dict[3] = "efg"
If you later need to assign it to a variable of NSDictionary
type, just do an explicit cast:
let nsDict = dict as! NSDictionary
And, as mentioned earlier, if you want to pass it to a function expecting NSDictionary
, pass it as-is without any cast or conversion.
Appending dictionary values to array in Swift
You should only sort the keys and then use that array to select from the dictionary and append your sortedValues
array. I made the sortedKeys
into a local variable
func sortItems() {
let sortedKeys = self.dictionary.keys.sorted(by: >)
for key in sortedKeys {
if let obj = dictionary[key] {
self.sortedValues.append(obj)
}
}
}
I don't know if this will make a difference in regard to the crash but another way is to let the function return an array
func sortItems() -> [Object] {
let sortedKeys = self.dictionary.keys.sorted(by: >)
var result: [Object]()
for key in sortedKeys {
if let obj = dictionary[key] {
result.append(obj)
}
}
return result
}
and then call it
self.sortedValues = sortItems()
How to determine if one array contains all elements of another array in Swift?
Instead of iterating through arrays and doing filtering yourself, you can use NSSet
to do all the work for you.
var list:Array<Int> = [1,2,3,4,5]
var findList:Array<Int> = [1,3,5]
let listSet = NSSet(array: list)
let findListSet = NSSet(array: findList)
let allElemtsEqual = findListSet.isSubsetOfSet(otherSet: listSet)
NSSet
is a lot faster than arrays at checking if it contains any object. In fact it's what it's designed for.
Edit: Using Swift's built-in Set
.
let list = [1,2,3,4,5]
let findList = [1,3,5]
let listSet = Set(list)
let findListSet = Set(findList)
//**Swift 4.2 and Above**
let allElemsContained = findListSet.isSubset(of: listSet)
//below versions
//let allElemsContained = findListSet.isSubsetOf(listSet)
Related Topics
Nsnotificationcenter Swift 3.0 on Keyboard Show and Hide
How Long Does Apple Permit a Background Task to Run
Fetching Selected Attribute in Entities
Perform Segue After Login Successful in Storyboards
Cabasicanimation Rotate Returns to Original Position
Undo with Multitouch Drawing in iOS
How to Use Uicolorfromrgb in Swift
Nsuserdefaults Losing Its Keys & Values When Phone Is Rebooted But Not Unlocked
Record, Save And/Or Convert Video in Mp4 Format
iOS Tableview Reload and Scroll Top
How to Scroll to a Particluar Index in Collection View in Swift
Exit Application When Click Button - iOS
Spritekit: Why Does It Wait One Round for the Score to Update? (Swift)
Thread Error in Ibaction While Overriding Prepareforsegue Function
Decrypt Value from Blowfish in Objective-C Code