0

I have a question and unfortunately not found anywhere responses.

I'll describe the problem in a simple example. I have an array of objects. Each object contains the id, name, count. This array is the result of parsing the data from the server. It is taken as the first.

I also have a second array taken from another server. This is the same array id, name, count.

My question is as follows. The first array has 20 elements, then each of this element I want to compare with an array of the other. The second array is the parse. You may need to use a loop and check whether every element in the first array is in the second or not?

//
//  ViewController.swift
//  ParseSearching
//
//  Created by Mateusz Fraczek on 21.07.2015.
//  Copyright (c) 2015 universeldev. All rights reserved.
//

import UIKit
import Parse

struct Model : Equatable {
    var ide: String!
    var name: String!
    var count: String!
}

func ==(a: Model, b: Model) -> Bool {
    return a.ide == b.ide && a.name == b.name && a.count == b.count
}

extension Array {

    func indexesOfSubset<T : Equatable>(objects : [T]) -> [Int] {

        // Create storage for filtered objects and results
        var unusedObjects = objects
        var result : [Int] = []

        // Enumerate through all objects in array
        for (index, obj) in enumerate(self) {

            // Enumerate again through all objects that has not been found
            for x in unusedObjects {

                // If we hit match, append result, remove it from usused objects
                if obj as! T == x {
                    result.append(index)
                    unusedObjects = unusedObjects.filter( { $0 != x } )
                    break
                }
            }
        }

        // Get results
        return result
    }
}

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        var firstArray = [Model]()
        var resultsArray = [Model]()


        firstArray.append(Model(ide: "xyz1", name: "name1", count: "0"))
        firstArray.append(Model(ide: "xyz2", name: "name2", count: "0"))
        firstArray.append(Model(ide: "xyz3", name: "name3", count: "0"))
        firstArray.append(Model(ide: "xyz4", name: "name4", count: "0"))

//        let testObject = PFObject(className: "TestObject")
//        testObject["ide"] = "xyz1"
//        testObject["name"] = "name1"
//        testObject["count"] = "0"
//        testObject.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
//            println("Object has been saved.")
//        }


        var query = PFQuery(className: "TestObject")

        query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
            if let object = objects as? [PFObject] {
                for obj in object {
                    var id = obj.objectForKey("ide") as! String
                    var name = obj.objectForKey("name") as! String
                    var count = obj.objectForKey("count") as! String

                    var model = Model(ide: id, name: name, count: count)

                    resultsArray.append(model)
                    println(resultsArray)
                    let indexes = firstArray.indexesOfSubset(resultsArray)

                    println("Indexes \(indexes) ")
                }
            }
        }



    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }



}
Maselko
  • 4,028
  • 2
  • 22
  • 21

4 Answers4

1

This is how you can do:

Swift 1:

var array = ["1", "2", "3"]
var contained = contains(array, "2")
println(contained ? "yes" : "no")

Swift 2:

var array = ["1", "2", "3"]
var contained = array.contains("2")
println(contained ? "yes" : "no")
Daljeet
  • 1,573
  • 2
  • 20
  • 40
0

I am in no way an expert but I would use isEqualToArray inside NSarray class.

The function inside the class compares the receiving array to another array.

SWIFT
func isEqualToArray(_ otherArray: [AnyObject]) -> Bool

Return Values
YES if the contents of otherArray are equal to the contents of the receiving array, otherwise NO

Xiddic
  • 17
  • 5
0

In order to find indexes of subset, it would be better to use something new in SWIFT, what do you say? So lets use generics and make solution that would work in the future, when your object changes, or you will use different objects altogether. Lets create extension to your array:

extension Array {

    func indexesOfSubset<T : Equatable>(objects : [T]) -> [Int] {

        // Create storage for filtered objects and results
        var unusedObjects = objects
        var result : [Int] = []

        // Enumerate through all objects in array
        for (index, obj) in enumerate(self) {

            // Enumerate again through all objects that has not been found
            for x in unusedObjects {

                // If we hit match, append result, remove it from usused objects
                if obj as! T == x {
                    result.append(index)
                    unusedObjects = unusedObjects.filter( { $0 != x } )
                    break
                }
            }
        }

        // Get results
        return result
    }
}

Now you can use this method to find objects using:

let sameIndexes = allData.indexesOfSubset(fetchedData)

Of course, fetched data and all data must be the same data type, in your case [Model]. You also have to make sure that you can compare those two objects properly, to do that, you have to create comparator taking your data type like this:

public func ==(a: Model, b: Model) -> Bool {
    return a.id == b.id && a.name == b.name && a.count == b.count
}

Also, in order for it to work, you have to make your object conform to Equatable protocol, so do that:

struct Model : Equatable {

Now when you compare two same Model objects, you will get compare == true and not an error :) Hope it helps!

Edit: Here is test gist where you can find everything including stuff from comments + how to use it

Jiri Trecak
  • 5,092
  • 26
  • 37
  • Error here: for (index, obj) in enumerate(self) – Maselko Jul 21 '15 at 07:38
  • I've edited my answer for your better understanding - you have to make it as extension to an array :) – Jiri Trecak Jul 21 '15 at 07:39
  • Thank you. But how can I use it with Model? In my code I can see cannot invoke indexesOfSubset with argument list of type Model. – Maselko Jul 21 '15 at 07:44
  • This method is made for searching array against array. So if you do `firstArray.indexesOfSubset([model])`, it should find you whether there is a match :) And of course, if you have more model objects, then you just do `firstArray.indexesOfSubset([model1, model2])`, and it will give you indexes in the first array, when it found a match. – Jiri Trecak Jul 21 '15 at 07:48
  • You should also extend `Model` with `Equatable` in order to make this work. – Qbyte Jul 21 '15 at 07:50
  • Ok looks nice, but there is problem with types. I still have error cannot invoke indexesOfSubset with argument list of type [Model] – Maselko Jul 21 '15 at 07:55
  • In my code it doesn't work. I don't know how to compre object from parse with firstArray. – Maselko Jul 21 '15 at 08:02
  • Here is an example, how to use this code: https://gist.github.com/JiriTrecak/57e5f860957d021a87a6 – Jiri Trecak Jul 21 '15 at 08:05
  • Then you can mark post as accepted answer, if it worked for you and it helped you :) It is a good practice. – Jiri Trecak Jul 21 '15 at 08:38
  • Post was marked but I have last question for you. Is it possible to change index which pass with modified data? – Maselko Jul 21 '15 at 08:47
  • Tell me, so you can finish it :) – Jiri Trecak Jul 21 '15 at 08:48
  • Is it possible to change index which pass with modified data? – Maselko Jul 21 '15 at 08:59
  • I've updated my gist with the method that does what you need: https://gist.github.com/JiriTrecak/57e5f860957d021a87a6 – Jiri Trecak Jul 21 '15 at 09:09
0

Use filter and contains

func == (lhs: SomeStruct, rhs: SomeStruct) -> Bool {
    return lhs.intConstant == rhs.intConstant && lhs.stringConstant == rhs.stringConstant
}

struct SomeStruct: Equatable {
    let intConstant:Int
    let stringConstant:String
}

var someStructOne = SomeStruct(intConstant: 1, stringConstant: "1")
var someStructTwo = SomeStruct(intConstant: 2, stringConstant: "2")
var someStructThree = SomeStruct(intConstant: 3, stringConstant: "4")
var someStructFour = SomeStruct(intConstant: 4, stringConstant: "4")
var someStructFive = SomeStruct(intConstant: 5, stringConstant: "5")


let structArrayOne = [someStructOne, someStructTwo, someStructThree]
let structArrayTwo = [someStructOne, someStructFour, someStructFive]

let structsInBothArrays = structArrayOne.filter({contains(structArrayTwo, $0)})

The trick here is making the struct conform to the Equatable ptotocol. You do this with the global function definition at the top which gives a definition of how to compare the two structs.

Neil Horton
  • 707
  • 6
  • 13