First of all, excuse me for my (sometimes) bad English, I'm french. I'm actually working on a role game project. The goal is to create a little macOS software (a generator) using Swift and Xcode that can create a potion (an effect associated with a potency) (like : "Fortify Speed 7/10") from multiple parameters. The app allows the user to enter two parameters : ingredients (selected in pop-up menus) and a dice roll (put in a text field). If those two (or more) ingredients have an effect in common, the soft makes an addition of the value of both effects and return this : ""effect in common" + (value of the 1st ingredient effect + value of 2nd ingredient effect)". The result can change during the operation depending on the dice roll, but it doesn't matter here.
Here is an exemple to understand what I'm saying :
1st ingredient : "Cat's Claw Bark" -> Resist Lightning (4/10); Resist Psychic (3/10); Acid Damage (3/10); Fear (3/10); Invisibility (1/10).
|| 2nd ingredient : "Grape Holly" -> Cure Disease (5/10); Resist Cold (4/10);
Heighten Medicine (4/10; Resist Lightning (3/10); Force Damage (2/10.
Because both ingredients have an effect in common (Resist Lightning), the soft returns that effect with an addition of the potency of the two effects.
So it returns : "Resist Lightning (7/10)"
Here is my first question : How can I convert this into Swift code ? I've tried many ways but nothing useful. I tried to use arrays, dictionaries, arrays into dictionaries, but I'm still facing the same problem : How can I attribute multiple parameters (effects in this case) and types (String for the name of the effect and Int for its potency) to an instance ? (If it's the right question). My second question is : How can I compare keys (not values) of a dictionary to match a result ?
Maybe like this, using a dictionary, but I'll need to display in the result not only the value of the key in the dictionary, but the key itself. Also, I'll need to compare the keys, not the values :
let grapeHolly: [String: Int] = ["Cure Disease": 5, "Resist Cold": 4, "Heighten Medicine": 4, "Resist Lightning": 3, "Force Damage": 2]
And by doing that I get a "Cannot use instance member 'grapeHolly' within property initializer" error. And if I put that line inside the body of a 'viewDidLoad()' function, it isn't recognize by the code that is not inside the function.
The UI of the app
To be clear and comprehensible, I want that when the user selects two or more ingredients from the second pop-ups menu (the first line of pop-ups are made to categorize ingredients into three categories "Common/Uncommon/Rare"), and when he push the "Make a potion" button, the result text field displays the result of the combination of both effects values, if they have an effect in common of course.
Tell me if you need me to be more precise, I'll be very happy to find help :)
Here is the code (don't care about the length of the ingredients list) :
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var ingredientRarityNorthlands: NSPopUpButton!
#IBOutlet weak var ingredientListNorthlands: NSPopUpButton!
#IBAction func ingredientRarityNorthlands(_ sender: NSPopUpButton) {
if ingredientRarityNorthlands.titleOfSelectedItem == "Common" {
ingredientListNorthlands.removeAllItems()
ingredientListNorthlands.addItems(withTitles: ingredientListNorthlandsCommon)
}
if ingredientRarityNorthlands.titleOfSelectedItem == "Uncommon" {
ingredientListNorthlands.removeAllItems()
ingredientListNorthlands.addItems(withTitles: ingredientListNorthlandsUncommon)
}
if ingredientRarityNorthlands.titleOfSelectedItem == "Rare" {
ingredientListNorthlands.removeAllItems()
ingredientListNorthlands.addItems(withTitles: ingredientListNorthlandsRare)
}
}
let ingredientListNorthlandsCommon = ["Black Pepper", "Bolean Violet", "Brittlebush Flower", "Brittlebush Resin", "Butterfly Moss", "Cardamom", "Cinnamon", "Cloves", "Colic Yellowcress", "Comb Mint", "Coriander (Leaves)", "Coriander (Seeds)", "Cork Tree Bark", "Crow Hood", "Cumin (Seeds)", "Desert Shrub", "Eucalyptus (Oil)", "Eucalyptus (Gum)", "Eucalyptus (Leaves)", "Eucalyptus (Seeds)", "Fire Itchweed", "Four-Leafed Colwort", "Frukmoot", "Ginger (Root)", "Jasmine (Flower)", "Life's Collard", "Lotus (Petals)", "Lotus (Seeds)", "Mango (Leaves)", "Mango (Taproot)", "Marigold (Flower)", "Marigold (Leaves)", "Mustard (Flower)", "Mustard (Greens)", "Mustard (Seeds)", "Nutmeg (Oil)", "Nutmeg (Seed)", "Radiant Azolla", "Red Chili (Seeds)", "Wall Snakeberry"]
let ingredientListNorthlandsUncommon = ["Aloe Vera", "Ash Gallberry", "Baby Zinnia", "Black Salt", "Buzzard Bile", "Corea Mint", "Dead Sage", "Dog Tongue", "Fennec Fox Droppings", "Giant Lizard Venom", "Marsupial Wolf Blood", "Noxious Laurel", "Ocort", "Orange Thyme", "Pale Penny Gilliflower", "Phoenix Briar", "Pocan Hemp", "Prickly Cane", "Serpent Rye", "Shivering Laurel", "Snage", "Two-Tongued Scorpion Tail", "Viper Venom"]
let ingredientListNorthlandsRare = ["Blackheart Flower", "Burrowing Vee Spider", "Jee Redzin Scorpion Eggs", "Kreetlee Leaves", "Olaart Buds", "Smouse Oil", "Wretch Salts", "Zettin Seeds"]
#IBAction func makeAPotion(_ sender: NSButton) {
if potionButton.isEnabled {
resultField.stringValue = result()
}
}
func result() -> String {
return "\(effect) \(value)"
}
}
Ps: I think it's not necessary but I put here the dice roll system :
var firstEffect = 10..<12
var secondEffect = 12..<15
var thirdEffect = 15..<20
var fourthEffect = 20..<25
var fifthEffect = 25...
var firstEffectEnabler: Bool = false
var secondEffectEnabler: Bool = false
var thirdEffectEnabler: Bool = false
var fourthEffectEnabler: Bool = false
var fifthEffectEnabler: Bool = false
#IBAction func diceRoll(_ sender: NSTextField) {
if diceRoll.stringValue == "\(firstEffect)" {
firstEffectEnabler = true
}
if diceRoll.stringValue == "\(secondEffect)" {
secondEffectEnabler = true
}
if diceRoll.stringValue == "\(thirdEffect)" {
thirdEffectEnabler = true
}
if diceRoll.stringValue == "\(fourthEffect)" {
fourthEffectEnabler = true
}
if diceRoll.stringValue == "\(fifthEffect)" {
fifthEffectEnabler = true
}
}
EDIT : So I tried this but I think it's a bit messy and not very optimized, and I don't really know if it could work. Also, there's still two problems : I don't know how to display the string "Grape Holly" in the ingredient list array and in the pop-up menu instead of "grapeHolly", and how to fix the "potency = grapeHolly[?]" line :
lazy var grapeHolly = ["Cure Disease": 5, "Resist Cold": 4, "Heighten Medicine": 4, "Resist Lightning": 3, "Force Damage": 2]
lazy var effect = Array(grapeHolly.keys)
var result: String = ""
lazy var potency = grapeHolly[]
func compare() {
func resultNorthlands() {
if ingredientListNorthlands.selectedItem?.doesContain(effect) == ((ingredientListMettina.selectedItem?.doesContain(effect))! || (ingredientListIsjord.selectedItem?.doesContain(effect))! || (ingredientListKaedmyr.selectedItem?.doesContain(effect))! || (ingredientListCouchant.selectedItem?.doesContain(effect))! || (ingredientListBlastlands.selectedItem?.doesContain(effect))!) {
var result = "\(effect)"
}
}
I think something could work but I get an error "Cannot subscript a value of type'[String: Int]' with an index of type '[String]'" on the "lazy var potency = grapeHolly[effect]" line. I don't really understand why... "dictionary[key]" isn't the way to get a key's value in a dictionary ? Also, I need to enter "grapeHolly" instead of the "Grape Holly" string in my ingredient list, do someone knows a way to fix this ?
(I made a 'grapeHollys' dictionary with orthographical mistakes except on the "Cure Disease" effect to match both effects lines as shown in the 'compare()' function)
About the 'compare()' function : I repeated as many times as the number of ingredient list, but changed the name of the first ingredient list (ingredientListNorthlands in this case) for each function repetition, to compare every ingredient list before the '==' operator with the other lists, so it's a bit long and repetitive, and I know it's not a good habit for a programmer to repeat itself, but that's all I've found yet.
But for now I can't build because of the error, so I can't test the efficiency of the code, that's why I'm asking you a bit of help :)
Here is the code :
//Properties
var result: String = ""
lazy var potency = grapeHolly[effect]
lazy var effect = Array(grapeHolly.keys)
lazy var grapeHolly = ["Cure Disease": 5, "Resist Cold": 4, "Heighten Medicine": 4, "Resist Lightning": 3, "Force Damage": 2]
lazy var grapeHollys = ["Cure Disease": 5, "Resist Cld": 4, "Heighten Mediine": 4, "Resist Lightnng": 3, "Force Damge": 2]
// Compare Function
func compare() {
func resultNorthlands() {
if ingredientListNorthlands.selectedItem?.doesContain(effect) == ((ingredientListMettina.selectedItem?.doesContain(effect))! || (ingredientListIsjord.selectedItem?.doesContain(effect))! || (ingredientListKaedmyr.selectedItem?.doesContain(effect))! || (ingredientListCouchant.selectedItem?.doesContain(effect))! || (ingredientListBlastlands.selectedItem?.doesContain(effect))!) {
var result = "\(effect) \(potency1 + potency2)"
}
}
//Potion Button
#IBAction func makeAPotion(_ sender: NSButton) {
compare()
if potionButton.isEnabled {
resultField.stringValue = result
}
}
Problem solved ! The solution was so obvious that I didn't think about it directly, the for-in loops ! I hope this will help anybody facing the same issue. Here is the corresponding code :
var selection = [
catClawBark: ["Resist Lightning": 5, "Resist Damage": 8],
grapeHolly: ["Resist Lightning": 6, "Resist Damage": 2]
]
for (ingredient, keys) in selection {
for key in keys {
for (ingredient2, keys2) in selection {
for key2 in keys2 {
if ingredient != ingredient2 {
if key.key == key2.key {
result = "You created a potion !\n---> \(key.key) \(key.value + key2.value) <---"
}
else {
result = "No match. Check the ingredients selected or retry when you have more !"
}
}
}
}
}
}
Related
I have two arrays, one an array of array of profiles and one of the section names:
var sections: [Array<Profile>] = [friends, contacts, other]
var sectionNames = ["Friends", "Contacts", "Other Users"]
How do I filter the names based on whether the sections are empty? I get an error when I try the code below:
sectionNames.filter { index, _ in
sections[index].count > 0
}
Contextual closure type '(String) throws -> Bool' expect 1 argument, but two given
You can use zip and compactMap:
let nonEmptySections = zip(sections, sectionNames).compactMap { $0.isEmpty ? nil : $1 }
Using zip has the advantage that you don't get crashes if the two arrays have different sizes. On the other hand, it can lead to subtle bugs.
I'd recommend that you use a data structure to model you data instead:
struct Section {
let name: String
let profiles: [Profile]
}
This should ease the way you process the sections in your app. And by using #Alexander's suggestion, you can add an isEmpty property to the struct, making it even easier to use
extension Section {
var isEmpty: Bool { return profiles.isEmpty }
}
... later in the code
let nonEmptySections = sections.filter { !$0.isEmpty }
you can try something like this
var ar1:[Array<Int>] = [[1,2],[3,4,],[],[5,6]]
var ar2 = [1,2,3,4]
ar2 = (0 ..< ar1.count).filter {ar1[$0].count > 0}.map {ar2[$0]}
print(ar2) // [1, 2, 4]
For the following code, how can I check if a member "b" or "f" exist for myArray?
struct example {
var a: String!
var b: Bool!
var c: Bool!
var d: String!
}
var myArray = [example]!
For example, if I check if member "f" exists, I would like something to return "false" or "nil"; and if I check if "b" exists, I would like to receive "true".
Thanks!
Unlike Objective-C, Swift does not have the dynamic mechanisms to do things like this. So the answer is that no, you cannot check for members by name in this way, unless you are working with members of an NSObject subclass which are marked with the #objc attribute.
Using Mirror.
let example = Example()
let containsB = Mirror(reflecting: example).children.contains { $0.0 == "b" } // true
let containsF = Mirror(reflecting: example).children.contains { $0.0 == "f" } // false
let examples = [Example(), Example(), Example()]
let containsA = examples.filter {
Mirror(reflecting: $0).children.contains { $0.0 == "a" }
}.isEmpty == false // true
As others have commented, there are other problems with your example, but assuming you know and are just throwing out a quick and dirty sample to illustrate your question, you could do something a bit like this:
if let bExists = myArray.b {
return true
} else if let fExists = myArray.f {
return false // or return nil, or whatever you want to do if `f exists.
}
This is a simple quiz app with a label and four buttons. I want code in the action button to execute by referencing the question in the if statement. (The problem with referencing the answer tag is that there are only four buttons, but more than four questions.) The code below gives an error that you can't use the binary operator. How can I make this work?
struct Question {
var Question : String!
var Answers : [String]!
var Answer : Int!
}
var Questions = [Question]()
var QNumber = Int()
var AnswerNumber = Int()
Questions = [Question(Question: "One", Answers: ["", "", "", ""], Answer: 0),
Question(Question: "Two", Answers: ["", "", "", ""], Answer: 1),
Question(Question: "Three", Answers: ["", "", "", ""], Answer: 2),
Question(Question: "Four", Answers: ["", "", "", ""], Answer: 3),
Question(Question: "Five", Answers: ["", "", "", ""], Answer: 0),]
func PickQuestion(){
if Questions.count > 0{
QNumber = 0
QLabel.text = Questions[QNumber].Question
AnswerNumber = Questions[QNumber].Answer
for i in 0..<Buttons.count{
Buttons[i].setTitle(Questions[QNumber].Answers[i], for: UIControlState.normal)
}
Questions.remove(at: QNumber)
}
#IBAction func Btn4(_ sender: Any) {
if(Question == "Five") {
//CODE THAT NEEDS TO EXECUTVE
} else if(Question == "Four") {
//EXECUTE A DIFFERENT CODE
}
Your question is super unclear and it looks like you would benefit from re-structuring your logic. That said, if this is a simple quiz app and you have a few buttons with tags 0, 1, 2 and 3 then you should simply be able to compare the Question's Answer property with the buttons tag and avoid comparing any strings altogether.
It's also not clear from your question how the "current question" is selected, so you may want to firm that one up too, I'd recommend storing the object in a var somewhere so you can do something like the following...
var currentQuestion:Question!
// Get the first question or something.
currentQuestion = Questions.first
#IBAction func buttonTapped(sender: UIButton) {
if sender.tag == currentQuestion.Answer {
print("You are a winner")
// Time to get a new question son.
}
}
The above code is untested and I hope it doesn't just confuse you further, however, in the current format your question may be closed as it is not completely clear what you are asking.
Edit:
Thanks for updating your question, It looks now like you are trying to compare the Question struct against the String "Five". these two objects are not comparable.
To make your code work you should use the AnswerNumber variable that you have made and check if the number matches like so.
#IBAction func Btn4(_ sender: Any) {
if AnswerNumber == 4 {
print("Correct Answer")
//CODE THAT NEEDS TO EXECUTVE
} else {
print("Wrong Answer")
//EXECUTE DIFFERENT CODE
}
}
Assuming you have an IBAction for each button you will need to repeat this for each, so Btn5 would look like this.
#IBAction func Btn5(_ sender: Any) {
if AnswerNumber == 5 {
...
Edit:
After chatting away, we figured out that you needed a custom action for each question (if the correct answer was selected). this took the form of an mp3 file that was played depending on which question it was.
We came to the conclusion that following the existing structure you should add another variable to hold the mp3 in the Question struct but also for the current question as below.
struct Question {
var Question : String!
var Answers : [String]!
var Answer : Int!
var audioFile: String!
}
var AnswerMP3 = ""
Then when we set the current question alongside AnswerNumber we can set the mp3 like so.
AnswerMP3 = Questions[QNumber].audioFile
Then in this way you do not need to have hardcoded actions for each question. the buttons simply pass the correct mp3 on to another method that plays the audio file.
if AnswerNumer == 4 {
playMP3File(AnswerMP3)
}
func playMP3File(fileName:String) {
// user the fileName to play the audio file.
}
I want to pass a Set<Int> as a parameter to a function. When I do:
let setsOfWinningCells: Set = [ [0,1,2], [3,4,5], [6,7,8], [0,3,6], [1,4,7], [2,5,8], [0,4,8], [2,4,6] ]
func isWinner(playerCells: Set<Int>) {
for winningCells in setsOfWinningCells {
if playerCells.isSupersetOf(winningCells) {
// do something
}
}
}
compiler complains it cannot invoke 'isSuperSetOf' with an argument list of type '(NSArray)'. Using Set<Int>() instead of Set<Int> also does not work.
Does anyone know the correct syntax? Thanks
Clarification:
I mistakenly thought the problem was passing the Set properly to the function but in fact the issue was not defining the Set of Set properly. Apologies for confusion.
winningCells is NSArray, you should pass a Set for isSupersetOf(_) function
Let's try to better define your problem.
The Group struct
Let's define a struct to represent the concept of a group of Int(s). We also want the struct to be Hashable.
struct Group: Hashable {
let values: Set<Int>
var hashValue: Int { return values.hashValue }
}
func ==(left:Group, right:Group) -> Bool {
return left.values == right.values
}
Winning Groups
Now lets create a list of winning groups
let winningGroups: Set<Group> = [
Group(values:[0,1,2]),
Group(values:[3,4,5]),
Group(values:[6,7,8]),
Group(values:[0,3,6]),
Group(values:[1,4,7]),
Group(values:[2,5,8]),
Group(values:[0,4,8]),
Group(values:[2,4,6])
]
Player Groups
Next we have a list of player groups
let playerGroups: Set<Group> = [
Group(values:[4,0,8]),
Group(values:[2,4,6])
]
Finding the Player Winning Groups (exact match)
Now we want to select all the Groups that are both in playerGroups and winningGroups.
let playerWinningGroups = playerGroups.intersect(winningGroups)
//[Group(values: Set([5, 4, 3])), Group(values: Set([2, 0, 1]))]
As you can ses the order of the Int(s) inside the Group is not relevant.
E.g. Player has [4,3,5] and a winning group is [3,4,5]. Even if the values are in different order the group is still added to the result.
Finding the Player Winning Groups (supersets)
Let's consider this player groups
let playerGroups: Set<Group> = [
Group(values:[4,0,8]),
Group(values:[2,4,6]),
Group(values:[6,7,8,9]),
]
The third group is a superset of the winning group [6,7,8,9]. However the previous solution does not pick this element.
Let's see a solution that returns also supergroups of the winningGroups
var res = Set<Group>()
playerGroups.forEach { (playerGroup) in
if (winningGroups.contains({ (winninGroup) -> Bool in return winninGroup.values.isSubsetOf(playerGroup.values) })) {
res.insert(playerGroup)
}
}
print(res) // [Group(values: Set([2, 4, 6])), Group(values: Set([6, 7, 9, 8])), Group(values: Set([4, 0, 8]))]
Thank you, Hamish, for pointing out what I missed. My issue was not passing the Set incorrectly but rather my Set of Set<Int> was not defined correctly. My original definition meant it was a Set of Arrays of Int. It should have been:
let setsOfWinningCells: Set<Set<Int>> = [ [0,1,2], [3,4,5], [6,7,8], [0,3,6], [1,4,7], [2,5,8], [0,4,8], [2,4,6] ]
In Swift, how can I check if an element exists in an array? Xcode does not have any suggestions for contain, include, or has, and a quick search through the book turned up nothing. Any idea how to check for this? I know that there is a method find that returns the index number, but is there a method that returns a boolean like ruby's #include??
Example of what I need:
var elements = [1,2,3,4,5]
if elements.contains(5) {
//do something
}
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 the Equatable protocol, compare e.g. Andrews's answer.
If the sequence elements are instances of a NSObject subclass
then you have to override isEqual:, 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")
}
For those who came here looking for a find and remove an object from an array:
Swift 1
if let index = find(itemList, item) {
itemList.removeAtIndex(index)
}
Swift 2
if let index = itemList.indexOf(item) {
itemList.removeAtIndex(index)
}
Swift 3, 4
if let index = itemList.index(of: item) {
itemList.remove(at: index)
}
Swift 5.2
if let index = itemList.firstIndex(of: item) {
itemList.remove(at: index)
}
Updated for Swift 2+
Note that as of Swift 3 (or even 2), the extension below is no longer necessary as the global contains function has been made into a pair of extension method on Array, which allow you to do either of:
let a = [ 1, 2, 3, 4 ]
a.contains(2) // => true, only usable if Element : Equatable
a.contains { $0 < 1 } // => false
Historical Answer for Swift 1:
Use this extension: (updated to Swift 5.2)
extension Array {
func contains<T>(obj: T) -> Bool where T: Equatable {
return !self.filter({$0 as? T == obj}).isEmpty
}
}
Use as:
array.contains(1)
If you are checking if an instance of a custom class or struct is contained in an array, you'll need to implement the Equatable protocol before you can use .contains(myObject).
For example:
struct Cup: Equatable {
let filled:Bool
}
static func ==(lhs:Cup, rhs:Cup) -> Bool { // Implement Equatable
return lhs.filled == rhs.filled
}
then you can do:
cupArray.contains(myCup)
Tip: The == override should be at the global level, not within your class/struct
I used filter.
let results = elements.filter { el in el == 5 }
if results.count > 0 {
// any matching items are in results
} else {
// not found
}
If you want, you can compress that to
if elements.filter({ el in el == 5 }).count > 0 {
}
Hope that helps.
Update for Swift 2
Hurray for default implementations!
if elements.contains(5) {
// any matching items are in results
} else {
// not found
}
(Swift 3)
Check if an element exists in an array (fulfilling some criteria), and if so, proceed working with the first such element
If the intent is:
To check whether an element exist in an array (/fulfils some boolean criteria, not necessarily equality testing),
And if so, proceed and work with the first such element,
Then an alternative to contains(_:) as blueprinted Sequence is to first(where:) of Sequence:
let elements = [1, 2, 3, 4, 5]
if let firstSuchElement = elements.first(where: { $0 == 4 }) {
print(firstSuchElement) // 4
// ...
}
In this contrived example, its usage might seem silly, but it's very useful if querying arrays of non-fundamental element types for existence of any elements fulfilling some condition. E.g.
struct Person {
let age: Int
let name: String
init(_ age: Int, _ name: String) {
self.age = age
self.name = name
}
}
let persons = [Person(17, "Fred"), Person(16, "Susan"),
Person(19, "Hannah"), Person(18, "Sarah"),
Person(23, "Sam"), Person(18, "Jane")]
if let eligableDriver = persons.first(where: { $0.age >= 18 }) {
print("\(eligableDriver.name) can possibly drive the rental car in Sweden.")
// ...
} // Hannah can possibly drive the rental car in Sweden.
let daniel = Person(18, "Daniel")
if let sameAgeAsDaniel = persons.first(where: { $0.age == daniel.age }) {
print("\(sameAgeAsDaniel.name) is the same age as \(daniel.name).")
// ...
} // Sarah is the same age as Daniel.
Any chained operations using .filter { ... some condition }.first can favourably be replaced with first(where:). The latter shows intent better, and have performance advantages over possible non-lazy appliances of .filter, as these will pass the full array prior to extracting the (possible) first element passing the filter.
Check if an element exists in an array (fulfilling some criteria), and if so, remove the first such element
A comment below queries:
How can I remove the firstSuchElement from the array?
A similar use case to the one above is to remove the first element that fulfils a given predicate. To do so, the index(where:) method of Collection (which is readily available to array collection) may be used to find the index of the first element fulfilling the predicate, whereafter the index can be used with the remove(at:) method of Array to (possible; given that it exists) remove that element.
var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]
if let indexOfFirstSuchElement = elements.index(where: { $0 == "c" }) {
elements.remove(at: indexOfFirstSuchElement)
print(elements) // ["a", "b", "d", "e", "a", "b", "c"]
}
Or, if you'd like to remove the element from the array and work with, apply Optional:s map(_:) method to conditionally (for .some(...) return from index(where:)) use the result from index(where:) to remove and capture the removed element from the array (within an optional binding clause).
var elements = ["a", "b", "c", "d", "e", "a", "b", "c"]
if let firstSuchElement = elements.index(where: { $0 == "c" })
.map({ elements.remove(at: $0) }) {
// if we enter here, the first such element have now been
// remove from the array
print(elements) // ["a", "b", "d", "e", "a", "b", "c"]
// and we may work with it
print(firstSuchElement) // c
}
Note that in the contrived example above the array members are simple value types (String instances), so using a predicate to find a given member is somewhat over-kill, as we might simply test for equality using the simpler index(of:) method as shown in #DogCoffee's answer. If applying the find-and-remove approach above to the Person example, however, using index(where:) with a predicate is appropriate (since we no longer test for equality but for fulfilling a supplied predicate).
An array that contains a property that equals to
yourArray.contains(where: {$0.propertyToCheck == value })
Returns boolean.
The simplest way to accomplish this is to use filter on the array.
let result = elements.filter { $0==5 }
result will have the found element if it exists and will be empty if the element does not exist. So simply checking if result is empty will tell you whether the element exists in the array. I would use the following:
if result.isEmpty {
// element does not exist in array
} else {
// element exists
}
Swift 4/5
Another way to achieve this is with the filter function
var elements = [1,2,3,4,5]
if let object = elements.filter({ $0 == 5 }).first {
print("found")
} else {
print("not found")
}
As of Swift 2.1 NSArrays have containsObjectthat can be used like so:
if myArray.containsObject(objectImCheckingFor){
//myArray has the objectImCheckingFor
}
Array
let elements = [1, 2, 3, 4, 5, 5]
Check elements presence
elements.contains(5) // true
Get elements index
elements.firstIndex(of: 5) // 4
elements.firstIndex(of: 10) // nil
Get element count
let results = elements.filter { element in element == 5 }
results.count // 2
Just in case anybody is trying to find if an indexPath is among the selected ones (like in a UICollectionView or UITableView cellForItemAtIndexPath functions):
var isSelectedItem = false
if let selectedIndexPaths = collectionView.indexPathsForSelectedItems() as? [NSIndexPath]{
if contains(selectedIndexPaths, indexPath) {
isSelectedItem = true
}
}
if user find particular array elements then use below code same as integer value.
var arrelemnts = ["sachin", "test", "test1", "test3"]
if arrelemnts.contains("test"){
print("found") }else{
print("not found") }
Here is my little extension I just wrote to check if my delegate array contains a delegate object or not (Swift 2). :) It Also works with value types like a charm.
extension Array
{
func containsObject(object: Any) -> Bool
{
if let anObject: AnyObject = object as? AnyObject
{
for obj in self
{
if let anObj: AnyObject = obj as? AnyObject
{
if anObj === anObject { return true }
}
}
}
return false
}
}
If you have an idea how to optimize this code, than just let me know.
Swift
If you are not using object then you can user this code for contains.
let elements = [ 10, 20, 30, 40, 50]
if elements.contains(50) {
print("true")
}
If you are using NSObject Class in swift. This variables is according to my requirement. you can modify for your requirement.
var cliectScreenList = [ATModelLeadInfo]()
var cliectScreenSelectedObject: ATModelLeadInfo!
This is for a same data type.
{ $0.user_id == cliectScreenSelectedObject.user_id }
If you want to AnyObject type.
{ "\($0.user_id)" == "\(cliectScreenSelectedObject.user_id)" }
Full condition
if cliectScreenSelected.contains( { $0.user_id == cliectScreenSelectedObject.user_id } ) == false {
cliectScreenSelected.append(cliectScreenSelectedObject)
print("Object Added")
} else {
print("Object already exists")
}
what about using a hash table for the job, like this?
first, creating a "hash map" generic function, extending the Sequence protocol.
extension Sequence where Element: Hashable {
func hashMap() -> [Element: Int] {
var dict: [Element: Int] = [:]
for (i, value) in self.enumerated() {
dict[value] = i
}
return dict
}
}
This extension will work as long as the items in the array conform to Hashable, like integers or strings, here is the usage...
let numbers = Array(0...50)
let hashMappedNumbers = numbers.hashMap()
let numToDetect = 35
let indexOfnumToDetect = hashMappedNumbers[numToDetect] // returns the index of the item and if all the elements in the array are different, it will work to get the index of the object!
print(indexOfnumToDetect) // prints 35
But for now, let's just focus in check if the element is in the array.
let numExists = indexOfnumToDetect != nil // if the key does not exist
means the number is not contained in the collection.
print(numExists) // prints true
Swift 4.2 +
You can easily verify your instance is an array or not by the following function.
func verifyIsObjectOfAnArray<T>(_ object: T) -> Bool {
if let _ = object as? [T] {
return true
}
return false
}
Even you can access it as follows. You will receive nil if the object wouldn't be an array.
func verifyIsObjectOfAnArray<T>(_ object: T) -> [T]? {
if let array = object as? [T] {
return array
}
return nil
}
You can add an extension for Array as such:
extension Array {
func contains<T>(_ object: T) -> Bool where T: Equatable {
!self.filter {$0 as? T == object }.isEmpty
}
}
This can be used as:
if myArray.contains(myItem) {
// code here
}