Removing Duplicate Objects from Fetch Based on Object Parameter Updated Swift

How to remove duplicate object in array?

You can try to do it like this:

guard let selectedPost = selectedPost else { return }
if selectedPost.media.contains(where: {$0.image == image}) { return } // Here the $0.image should be replaced with $0.mediaURL == mediaURL for the videos or however you videoURL is called in Media
selectedPost.media.append(Media(image: image, timeStamp: Double(timeStamp)))
self.tableView.reloadData()

Try conforming Hashable in you Media class:

class Media : Hashable {

var hashValue : Int {
return image.hashValue
}

var image = UIImage()
// .....

static func == (lhs: Media, rhs: Media) -> Bool {
return lhs.hashValue == rhs.hashValue
}

}

Then you can compare two media objects with ==, So you can do something similar to the top part of this answer. Good luck

Remove Duplicate objects from JSON Array

Ultimately, I need a list with the each unique grade as the header and the unique domains as the list items to pass into an HTML page. I may be going about this wrong, so if there is an easier way to accomplish that end goal, I am open to ideas.

So you don't actually need that output array in the format you asked about.

That being the case, I would cut directly to the chase with a very simple and efficient solution:

var grades = {};
standardsList.forEach( function( item ) {
var grade = grades[item.Grade] = grades[item.Grade] || {};
grade[item.Domain] = true;
});

console.log( JSON.stringify( grades, null, 4 ) );

The resulting grades object is:

{
"Math K": {
"Counting & Cardinality": true,
"Geometry": true
},
"Math 1": {
"Counting & Cardinality": true,
"Orders of Operation": true
},
"Math 2": {
"Geometry": true
}
}

One interesting thing about this approach is that it is very fast. Note that it makes only a single pass through the input array, unlike other solutions that require multiple passes (whether you write them yourself or whether _.uniq() does it for you). For a small number of items this won't matter, but it's good to keep in mind for larger lists.

And with this object you now have everything you need to run any code or generate any other format you want. For example, if you do need the exact array output format you mentioned, you can use:

var outputList = [];
for( var grade in grades ) {
for( var domain in grades[grade] ) {
outputList.push({ Grade: grade, Domain: domain });
}
}

JSON.stringify( outputList, null, 4 );

This will log:

[
{
"Grade": "Math K",
"Domain": "Counting & Cardinality"
},
{
"Grade": "Math K",
"Domain": "Geometry"
},
{
"Grade": "Math 1",
"Domain": "Counting & Cardinality"
},
{
"Grade": "Math 1",
"Domain": "Orders of Operation"
},
{
"Grade": "Math 2",
"Domain": "Geometry"
}
]

Rai asks in a comment how this line of code works:

var grade = grades[item.Grade] = grades[item.Grade] || {};

This is a common idiom for fetching an object property or providing a default value if the property is missing. Note that the = assignments are done in right-to-left order. So we could translate it literally to use an if statement and a temp variable:

// Fetch grades[item.Grade] and save it in temp
var temp = grades[item.Grade];
if( ! temp ) {
// It was missing, so use an empty object as the default value
temp = {};
}
// Now save the result in grades[item.Grade] (in case it was missing)
// and in grade
grades[item.Grade] = temp;
var grade = temp;

You may notice that in the case where grades[item.Grade] already exists, we take the value we just fetched and store it back into the same property. This is unnecessary, of course, and you probably wouldn't do it if you were writing the code out like this. Instead, you would simplify it:

var grade = grades[item.Grade];
if( ! grade ) {
grade = grades[item.Grade] = {};
}

That would be a perfectly reasonable way to write the same code, and it's more efficient too. It also gives you a way to do a more specific test than the "truthiness" that the || idiom relies on. For example instead of if( ! grade ) you might want to use if( grade === undefined ).

Filtering unique names of an array with massive amount of objects

@MartinR solved this by using Sets.

My new updated struct

struct StreetName: Hashable {
static func == (lhs: StreetName, rhs: StreetName) -> Bool {
return lhs.name == rhs.name
}

var hashValue: Int {
return name.hashValue
}

var name: String
var polyLine: CLLocationCoordinate2D
}

My new updated code

DataManager.shared.getStreetNames { (returnedNamesSet) in
var namesArray: [StreetName] = Array(returnedNamesSet)

self.streetNames = namesArray.sorted(by: {$0.name < $1.name})
self.filteredStreetNames = self.streetNames
OperationQueue.main.addOperation {
self.streetTableView.reloadData()
}
}


Results:

The process time went from 30 seconds to 0.4 seconds by using Set

Removing duplicate elements from an array in Swift

You can roll your own, e.g. like this:

func unique<S : Sequence, T : Hashable>(source: S) -> [T] where S.Iterator.Element == T {
var buffer = [T]()
var added = Set<T>()
for elem in source {
if !added.contains(elem) {
buffer.append(elem)
added.insert(elem)
}
}
return buffer
}

let vals = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let uniqueVals = uniq(vals) // [1, 4, 2, 6, 24, 15, 60]

And as an extension for Array:

extension Array where Element: Hashable {
func uniqued() -> Array {
var buffer = Array()
var added = Set<Element>()
for elem in self {
if !added.contains(elem) {
buffer.append(elem)
added.insert(elem)
}
}
return buffer
}
}

Or more elegantly (Swift 4/5):

extension Sequence where Element: Hashable {
func uniqued() -> [Element] {
var set = Set<Element>()
return filter { set.insert($0).inserted }
}
}

Which would be used:

[1,2,4,2,1].uniqued()  // => [1,2,4]

Removing Duplicates From Array of Custom Objects Swift

You can do it with a set of strings, like this:

var seen = Set<String>()
var unique = [DisplayMessage]
for message in messagesWithDuplicates {
if !seen.contains(message.id!) {
unique.append(message)
seen.insert(message.id!)
}
}

The idea is to keep a set of all IDs that we've seen so far, go through all items in a loop, and add ones the IDs of which we have not seen.

adding objects in array creates duplicate values in swift

First of all never print a meaningless literal string like "Error" in a catch block. Print always the error instance.

Animal is obviously a class (reference type). You are creating one instance and the properties are updated in the loop. As always the same instance is used the values are overwritten and you get result.count items with the same contents.

Create new instances inside the loop and replace Entity with the real entity name

var tempArr = [AnimalViewModel]()

do {
let result = try managedContext.fetch(fetchRequest) as! [Entity] // let !
for ds in result {

let objAnimal = Animal() // let !
objAnimal.name = ds.name
objAnimal.type = ds.type

let objAVM = AnimalViewModel(aniModel: objAnimal) // let !
tempArr.append(objAVM)
}
} catch {
print(error)
}

And please notice and fix the warnings about never mutated variables



Related Topics



Leave a reply



Submit