Remove objects that have duplicate keys - ios

My code...
class Inbox {
var user = "name"
var pmsg = "label"
var match = ""
var resim = "photo"
var userID = ""
var distance = ""
var updated = ""
var isAttendingNow = ""
var isAttendingNowText = ""
init(user : String, pmsg: String, match: String, resim: String, userID : String, distance: String, updated: String, isAttendingNow: String, isAttendingNowText: String) {
self.user = user
self.pmsg = pmsg
self.match = match
self.resim = resim
self.userID = userID
self.distance = distance
self.updated = updated
self.isAttendingNow = isAttendingNow
self.isAttendingNowText = isAttendingNowText
}
}
var arrayOfRels: [Inbox] = [Inbox]()
My goal is to remove duplicate items for userID key.
How can I achieve that?

You could use a set to figure out which useIDs are unique:
func filteredRels(source [Inbox]) -> [Inbox] {
var keys: Set<String> = []
return source.filter {
if keys.contains($0.userID) {
return false
} else {
keys.insert($0.userID)
return true
}
}
}
(Banged out in the editor, so it might need some minor cleanup.)

Use Hashable
class RRR : Hashable {
var hashValue: Int = 0
static func == (lhs: RRR, rhs: RRR) -> Bool {
// in your case set only userID
return lhs.name == rhs.name && lhs.age == rhs.age
}
var name:String
var age:Int
init(name:String,age:Int) {
self.name = name
self.age = age
}
}
//
let arr = [RRR(name: "qqq", age: 12) ,RRR(name: "qqq", age: 12) , RRR(name: "hhhh", age: 12) , RRR(name: "ppppp", age: 12) ]
let set = Array(Set(arr))
print(set) // [ RRR(name: "qqq", age: 12) , RRR(name: "hhhh", age: 12) , RRR(name: "ppppp", age: 12)]

Checkout this:
extension Sequence where Iterator.Element: Hashable {
func uniqueOrdered() -> [Iterator.Element] {
return reduce([Iterator.Element]()) { $0.contains($1) ? $0 : $0 + [$1] }
}
}
class Inbox: Hashable {
...
...
static func == (lhs: User, rhs: User) -> Bool {
return lhs.userID == rhs.userID
}
}
arrayOfRels.uniqueOrdered()

You could do this in a couple of lines using a set:
var unique = Set<String>()
arrayOfRels = arrayOfRels.filter{unique.insert($0.userID).inserted}

Related

Access element of the struct in array of structs

Hi I have a task to implement the Fleet protocol which has two functions:
addNewCar - adds a new car object to the Fleet.
- Parameter car: car to add to the Fleet
- Returns: false if the car with same id already exists in the Fleet, true – otherwise.
deleteCar - Deletes the car with the specified id from the Fleet.
- Returns: true if the car with same id existed in the Fleet, false – otherwise.
listCarsByModel - returns 10 car models containing the specified string.
If there are several cars with the same model, brand's name is added to car's model in the format "brand - car",
otherwise returns simply "car".
listCarsByBrand - returns 10 car models whose brand contains the specified string,
result is ordered by brand.
struct Car {
let id: String; // unique identifier
let model: String;
let brand: String;
}
protocol Fleet {
func addNewCar(car: Car) -> Bool
func deleteCar(id: String) -> Bool
func listCarsByModel(searchString: String) -> Set<String>
func listCarsByBrand(searchString: String) -> [String]
}
class FleetImpl: Fleet {
var cars: [Car] = []
func addNewCar(car: Car) -> Bool {
if let i = cars.firstIndex(where: { $0.id == car.id }) {
print(i)
return false
} else {
cars.append(car)
print(car)
return true
}
}
func deleteCar(id: String) -> Bool {
return true
}
func listCarsByModel(searchString: String) -> Set<String> {
}
func listCarsByBrand(searchString: String) -> [String] {
}
}
I've used method firstIndex(where:). But the function adds new car to the array with existing id. (i.e. two or more cars with the same id)
How can I access that 'id' property of Car struct in order to manipulate that data?
Please help me out
This is the test code:
func test(fleet: Fleet) {
assert(!fleet.deleteCar(id: "1"))
assert(fleet.addNewCar(car: Car(id: "1", model: "1", brand: "Lex")))
assert(!fleet.addNewCar(car: Car(id: "1", model: "any name because we check id only", brand: "any brand")))
assert(fleet.deleteCar(id: "1"))
assert(fleet.addNewCar(car: Car(id: "3", model: "Some Car3", brand: "Some Brand2")))
assert(fleet.addNewCar(car: Car(id: "4", model: "Some Car1", brand: "Some Brand3")))
var byModels: Set<String> = fleet.listCarsByModels(searchString: "Car")
assert(byModels.count == 10)
byModels = fleet.listCarsByModels(searchString: "Some Car")
assert(byModels.count == 4)
assert(byModels.contains("Some Brand3 - Some Car1"))
assert(byModels.contains("Some Car2"))
assert(byModels.contains("Some Car3"))
assert(!byModels.contains("Some Car1"))
assert(byModels.contains("Some Brand1 - Some Car1"))
var byBrand: [String] = fleet.listCarsByBrand(searchString: "Brand")
assert(byBrand.count == 10)
byBrand = fleet.listCarsByBrand(searchString: "Some Brand")
assert(byBrand.count == 4)
assert(byBrand[0] == "Some Car1")
assert(byBrand[1] == "Some Car2" || byBrand[1] == "Some Car3")
assert(byBrand[2] == "Some Car2" || byBrand[2] == "Some Car3")
assert(byBrand[3] == "Some Car1")
}
test(fleet: FleetImpl())
Maybe a set instead of an array would work better in this case as we're dealing with unique elements. Also note that rather than using firstIndex(where) I'm using first(where) which will return the car rather than index.
import UIKit
struct Car: Hashable {
let id: String
let model: String
let brand: String
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
protocol Fleet {
func addNewCar(car: Car) -> Bool
func deleteCar(id: String) -> Bool
func listCarsByModel(searchString: String) -> [String]
func listCarsByBrand(searchString: String) -> [String]
}
class FleetImpl: Fleet {
var cars = Set<Car>()
func addNewCar(car: Car) -> Bool {
guard !cars.contains(where: { $0.id == car.id }) else { return false }
cars.insert(car)
return true
}
func deleteCar(id: String) -> Bool {
guard let car = cars.first(where: { $0.id == id }) else { return false }
cars.remove(car)
return true
}
func listCarsByModel(searchString: String) -> [String] {
let searchedCars = cars.filter { $0.model.lowercased().contains(searchString.lowercased()) }.sorted { $0.brand < $1.brand }
var formattedModels = [String]()
searchedCars.forEach { car in
if let car = searchedCars.first(where: { $0.model == car.model && $0.id != car.id }) {
let carName = [car.model, car.brand].joined(separator: " - ")
formattedModels.append(carName)
} else {
formattedModels.append(car.model)
}
}
return Array(formattedModels.prefix(10))
}
func listCarsByBrand(searchString: String) -> [String] {
let searchedBrands = cars.filter { $0.brand.lowercased().contains(searchString.lowercased()) }.sorted { $0.brand < $1.brand }.map { $0.model }
return Array(searchedBrands.prefix(10))
}
}

How to filter other parent of child with Vapor?

I have this request:
router.get("/fetchOngoingReleases") { (request) -> Future<[ReleaseOut]> in
return Release.query(on: request).filter(\.inprogress == true).all().map { releases in
var result: [ReleaseOut] = []
for r in releases {
var pageEvents: [Event] = []
let num = r.releaseUsers.query(on: request).filter(\.user.fbId ~~ "something").count()
var needAuthentication: Bool
if num == 0 {
needAuthentication = true
} else {
needAuthentication = false
}
let rOut = ReleaseOut(fbId: r.fbId, name: r.name, purpose: r.purpose, needAuthentication: needAuthentication)
result.append(rOut)
}
return result
}
}
}
It says I can not access (???) releaseUser.user.fbId in the query?
Here the data model:
and in code
final class Release: Content {
var id: Int?
var fbId: String
var inprogress: Bool?
var name: String
var purpose: String
/// Creates a new `Release`.
init(id: Int? = nil, fbId: String, name: String, purpose: String = "normal selling") {
self.id = id
self.fbId = fbId
self.name = name
self.purpose = purpose
}
}
extension Release {
var releaseUsers: Children<Release, ReleaseUser> {
return children(\.releaseId)
}
}
final class ReleaseUser: Content {
var id: Int?
var releaseId: Release.ID
var userId: User.ID
init(id: Int? = nil, releaseId: Release.ID, userId: User.ID) {
self.id = id
self.releaseId = releaseId
self.userId = userId
}
}
extension ReleaseUser {
var user: Parent<ReleaseUser, User> {
return parent(\.userId)
}
}
final class User: Content {
var id: Int?
var fbId: String
var name: String
init(id: Int? = nil, fbId: String, name: String) {
self.id = id
self.fbId = fbId
self.name = name
}
}
Ok so there are several things going on here, but the main concept is that you can't just jump across different tables like that - you need to use a JOIN to join the ReleaseUser table to the User table so you can then query on the fbId
Try changing your query to:
Release.query(on: request).filter(\.inprogress == true).join(\ReleaseUser.releaseId, to:\Release.Id).join(\ReleaseUser.userId, to:\User.Id).alsoDecode(User.self).all()
The alsoDecode will give you a tuple with the first position containing your original Release instance and the second containing the corresponding User instance. So, fbId should be available as:
r.1.fbId
In your case.

How to remove duplicate items from an array with multiple criteria?

Objective: I have to delete object from array which has same title, vicinity, coordinate.latitude and coordinate.longitude
class Place {
var placeID: String?
var title: String?
var vicinity: String?
var detailsUrl: String?
var openingHours: OpeningHours?
var position: [Double]
var coordinate: CLLocationCoordinate2D {
return CLLocationCoordinate2DMake(position.first ?? 0, position.last ?? 0)
}
One way i have tried that -
extension Array {
func removingDuplicates <T: Hashable>(byKey key: (Element) -> T) -> [Element] {
var result = [Element]()
var seen = Set<T>()
for value in self {
if seen.insert(key(value)).inserted {
result.append(value)
}
}
return result
}
}
let array = list.removingDuplicates(byKey: { "\($0.coordinate.latitude)" + "\($0.coordinate.longitude)" + ($0.title ?? " ") + ($0.vicinity ?? " ") })
But i really don't like above solution. What is the most appropriate way to handle it ?
Add Equatable to the Place class
class Place: Equatable {
static func == (lhs: Place, rhs: Place) -> Bool {
return lhs.title == rhs.title && lhs.vicinity == rhs.vicinity &&
lhs.coordinate.latitude == rhs.coordinate.latitude && lhs.coordinate.longitude == rhs.coordinate.longitude
}
//...
}
And filter the array elements with the place/places to delete
var list = [Place]()
//Delete multiple places
let placesToDelete = [Place]()
let result = list.removeAll { placesToDelete.contains($0) }
//Delete one place
let placeToDelete = Place()
let result = list.removeAll { $0 == placeToDelete }

Realm add(_, update: true) removes existing relationships

I am facing an issue where I am unable to keep existing relationships after calling add(_, update: true) function.
I wrote a TaskSync class that is responsible for creating/updating Task objects:
class TaskSync: ISync {
typealias Model = Task
func sync(model: Task) {
let realm = try! Realm()
let inWrite = realm.isInWriteTransaction
if !inWrite {
realm.beginWrite()
}
let _task = realm.object(ofType: Task.self, forPrimaryKey: model.id)
// Persist matches as they are not getting fetched with the task
if let _task = _task {
print("matches: \(_task.matches.count)")
model.matches = _task.matches
}
realm.add(model, update: true)
if _task == nil {
var user = realm.object(ofType: User.self, forPrimaryKey: model.getUser().id)
if (user == nil) {
user = model.getUser()
realm.add(user!, update: true)
}
user!.tasks.append(model)
}
if !inWrite {
try! realm.commitWrite()
}
}
func sync(models: List<Task>) {
let realm = try! Realm()
try! realm.write {
models.forEach { task in
sync(model: task)
}
}
}
}
When a model is to be synced, I check if it already exists in the Realm and if so, I fetch it and try to include the matches property as this one is not included in the model.
Right before the call realm.add(model, update: true), model contains list of matches, however right after the realm.add is executed, the matches list is empty.
Here are the two models:
class Task: Object, ElementPreloadable, ElementImagePreloadable, ItemSectionable {
dynamic var id: Int = 0
dynamic var title: String = ""
dynamic var desc: String = ""
dynamic var price: Float = 0.0
dynamic var calculatedPrice: Float = 0.0
dynamic var location: String = ""
dynamic var duration: Int = 0
dynamic var date: String = ""
dynamic var category: Category?
dynamic var currency: Currency?
dynamic var longitude: Double = 0.0
dynamic var latitude: Double = 0.0
dynamic var state: Int = 0
dynamic var userId: Int = 0
// Existing images
var imagesExisting = List<URLImage>()
// New images
var imagesNew = List<Image>()
// Images deleted
var imagesDeleted = List<URLImage>()
private let users = LinkingObjects(fromType: User.self, property: "tasks")
var user: User?
var matches = List<Match>()
dynamic var notification: Notification?
override static func ignoredProperties() -> [String] {
return ["imagesExisting", "imagesNew", "imagesDeleted", "user", "tmpUser"]
}
override static func primaryKey() -> String? {
return "id"
}
func getImageMain() -> URLImage? {
for image in imagesExisting {
if image.main {
return image
}
}
return imagesExisting.first
}
func getSection() -> Int {
return state
}
func getSectionFieldName() -> String? {
return "state"
}
func getId() -> Int {
return id
}
func getURL() -> URL? {
if let image = getImageMain() {
return image.getResizedURL()
}
return nil
}
func getState() -> TaskOwnState {
return TaskOwnState(rawValue: state)!
}
func getUser() -> User {
return (user != nil ? user : users.first)!
}
}
class Match: Object, ElementPreloadable, ElementImagePreloadable, ItemSectionable {
dynamic var id: Int = 0
dynamic var state: Int = -1
dynamic var priorityOwnRaw: Int = 0
dynamic var priorityOtherRaw: Int = 0
dynamic var user: User!
var messages = List<Message>()
private let tasks = LinkingObjects(fromType: Task.self, property: "matches")
var task: Task?
dynamic var notification: Notification?
override static func primaryKey() -> String? {
return "id"
}
override static func ignoredProperties() -> [String] {
return ["task"]
}
func getId() -> Int {
return id
}
func getSection() -> Int {
return 0
}
func getURL() -> URL? {
if let image = user.getImageMain() {
return image.getResizedURL()
}
return nil
}
func getPriorityOwn() -> PriorityType {
if priorityOwnRaw == PriorityType.normal.rawValue {
return PriorityType.normal
}
else {
return PriorityType.favorite
}
}
func getPriorityOther() -> PriorityType {
if priorityOtherRaw == PriorityType.normal.rawValue {
return PriorityType.normal
}
else {
return PriorityType.favorite
}
}
func getSectionFieldName() -> String? {
return nil
}
func getTask() -> Task {
return (task != nil ? task : tasks.first)!
}
}
I spent hours trying to figure out why I am unable to keep the matches relationship when updating the task. Every advice will be highly appreciated!
This question was also asked upon Realm's GitHub issue tracker. For posterity, here is the solution.
List properties should always be declared as let properties, as assigning to them does not do anything useful. The correct way to copy all objects from one List to another is model.tasks.append(objectsIn: _user.tasks).

How to sort NSMutableArray that contains object of type Modal?

I’ve an NSMutableArray (say accountListArray). The content of array is Model (say BankAccountModel with property defaultAcc - Y/N).
Now I want to sort the content of accountListArray based on default property i.e. all account that is defaultAcc enabled (Y) should be on top.
class BankAccountModel: NSObject {
static let sharedInstance: BankAccountModel = BankAccountModel()
var defaultAcc = "" // Y or N
}
How to do it?
Here is my example. It will sort array and after sort person with name 2 and person with name 4 will be in top of the array
class People{
var name = ""
var isMale:Bool = false
init(name:String,isMale:Bool){
self.name = name
self.isMale = isMale
}
}
var person1 = People(name: "1",isMale: false)
var person2 = People(name: "2",isMale: true)
var person3 = People(name: "3",isMale: false)
var person4 = People(name: "4",isMale: true)
var array = [person1,person2,person3,person4]
array.sort() { Int(NSNumber(value:($0.isMale))) > Int(NSNumber(value:($1.isMale))) }
Additional to the answers above. You can define your model as Comparable, then implement your own >, <, == protocol:
For example:
class BankAccountModel: Comparable { //or struct
var accountHolder: String = ""
var balance: Decimal?
var enabled: Bool = false
init(holder: String, balance: Decimal, enabled: Bool) {
self.accountHolder = holder
self.balance = balance
self.enabled = enabled
}
static func == (lhs: BankAccountModel, rhs: BankAccountModel) -> Bool {
return lhs.enabled == rhs.enabled
}
static func > (lhs: BankAccountModel, rhs: BankAccountModel) -> Bool {
return lhs.enabled || (!lhs.enabled && !rhs.enabled)
}
static func < (lhs: BankAccountModel, rhs: BankAccountModel) -> Bool {
return rhs.enabled || (!rhs.enabled && !lhs.enabled)
}
}
let account1 = BankAccountModel(holder: "Holder 1", balance: Decimal(10.0), enabled: true)
let account2 = BankAccountModel(holder: "Holder 2", balance: Decimal(20.3), enabled: false)
let account3 = BankAccountModel(holder: "Holder 3", balance: Decimal(-1.0), enabled: false)
let account4 = BankAccountModel(holder: "Holder 4", balance: Decimal(0.0), enabled: true)
var allAccounts = [account1, account2, account3, account4]
allAccounts.sort(by: {return $0 > $1})
Try this :
Create Model property as below
class BankAccountModel: NSObject {
static let sharedInstance: BankAccountModel = BankAccountModel()
var isDefault: Bool = false
// assign value
if let objDefault = dictionary["default"] {
isDefault = (objDefault as! String) == "Y" ? true : false
}
// var default = "" // Y or N
}
Sort as below
self.arrOfModels.sort {
return $0.isDefault && !$1.isDefault // isSelected is your flag . you need to change with your flag
}
OR
Another Solution with string
self.arrModels.sort {
return ($0. defaultAcc == "Y") && ($1. defaultAcc == "N")
}
Swift 3.0
Hope will work for you.
let sortedArr = accountListArray.sorted(by: {
let item1 = $0 as! BankAccountModel
let item2 = $1 as! BankAccountModel
if item1.defaultAcc > item2.defaultAcc {
return true
}
return false
})

Resources