Lodash choose which duplicates to reject - lodash

I have array of objects, objects have properties say "a", "b" and "c".
Now I need to filter out objects which has unique values of "a & b".
However c plays role on which objects to keep and which ones to reject.
If I do uniqBy on properties a and b, I will be blindly rejecting other objects. It will keep the first object it encounters in the array and reject all other duplicates.
Let me know if you need more clarification on the question.
This is how I found the uniq objects based on two properties.
var uniqArray= _.uniqBy(obj, function(elem) { return [elem.a, elem.b].join(); })
lodash uniq - choose which duplicate object to keep in array of objects
Do we have better solution?
Here is an example of input and expected output
Input: var arrayOfObj = [{a:1, b:1, c:2}, {a:1,b:1,c:1}, {a:2, b:2,c:2}];
Output: arrayOfObj = [{a:1,b:1,c:1}, {a:2, b:2,c:2}]; there should not be any duplicate a1,b1 combination

According to Lodash documentation, the order of result values is determined by the order they occur in the array. Therefore you need to order the array using the 'c' property in order to get the expected result.
To do so, you can use _.sortBy. It orders a collection in asc order based on a property or an iteratee. I think your problem could be solved using a property directly though you could use a function to provide a more accurate comparator if needed.
After that, you just perform the uniqBy action and retrieve the result:
var res = _(arrayOfObj)
.orderBy('c')
.uniqBy('a', 'b')
.value();
console.log(res);
Here's the fiddle.
As I read in the comments, your 'c' property is a timestamp. If you want to order from latest to newest, you can pass an iteratee to sort by in order to reverse the natural order by 'c':
var res = _(arrayOfObj)
.orderBy(function(obj) {
return -(+obj.c);
})
.uniqBy('a', 'b')
.value();
console.log(res);
You can check it out in this update of the previous fiddle. Hope it helps.

Would help to know what the actual data is and what you want to achieve with it. Here's an idea: group your objects based on a and b, then from each grouping, select one item based on c.
var arrayOfObj = [
{a:1, b:1, c:2},
{a:1, b:1, c:1},
{a:2, b:2, c:2}
];
var result = _.chain(arrayOfObj)
.groupBy(function (obj) {
return obj.a.toString() + obj.b.toString();
})
.map(function (objects) {
//replace with code to select the right item based on c
return _.head(objects);
}).value();

Related

How to delete items from an array in Vue

I have a function called updateAnswer with multiple dynamic parameters.
updateAnswer(key, answer, array = false) {
if (array) {
if(this.answers.contains.find(element => element === answer)) {
//Delete item from array if already element already exists in this.answers.contains array.
} else {
Vue.set(this.answers, key, [...this.answers.contains, answer]);
}
} else {
Vue.set(this.answers, key, answer);
}
},
I'd like to know how delete an item in the array if the value already exists in the array.
You can use method called splice:
Just reference on your array and set values in the brackets the first is referenced on the position, the second is how many datas you want to splice/delete.
The function looks like this:
this.array.splice(value, value)
Lets see on an example - you have array food= [apple, banana, strawberry] than I'm using this.food.splice(1,1)..
my array looks now like this food = [apple, strawberry] - first value in my brackets are the position, the second one is the amount of "numbers" you want to delete.
Hopefully this helps you out!
I suppose each value in this.answers.contains is unique?
Anyways, if you just want to delete the item if already exists, I suggest filter(). It should look like below:
if(this.answers.contains.find(element => element === answer)) {
this.answers.contains = this.answers.contains.filter(c => c !== answer)
}
Also, the if condition if(this.answers.contains.find(element => element === answer)) could also be replaced by if(this.answers.contains.includes(answer))
Hope that could help you.

How to sort flatlist in React Native?

I have data stored in a state that is shown in flatlist, I want to sort the data based on ratings. So if I click on sort button they should be sorted in ascending order and when I click again, they should be sorted in descending order.
I have an array of objects stored in state, below is just a piece of data that is important.
show_data_list = [{ ratings : { overall : 4, ...other stuff } } ]
Is there a way I could do it, I tried using the map function which sorts array
list.map((a,b) => a-b)
But how can I use this to sort my array of objects, I cant pass in 2 item.rating.overall as the parameter.
Thanks in advance for the help :)
You can use javascript's built in sort function. You can provide a custom comparer function for it, which should return a negative value if the first item takes precedence, 0 if they are the same and a positive value if the second value should take precedence.
show_data_list.sort((a, b) => { return a.ratings.overall - b.ratings.overall; }). This will sort the data in the ascending order.
show_data_list.sort((a, b) => { return b.ratings.overall - a.ratings.overall; }). This will sort it in the descending order.
This is how I solved it stored the data in a variable and then sorted it based on condition
let rating = this.state.show_data_list;
rating.sort(function(a,b) {
return a.ratings.Overall < b.ratings.Overall
Try This
Sort your List Ascending/ Descending order with name or other string value in list
const [productSortList, setProductSortList] = useState(productarray);
where productarray is your main array
Ascending
productarray.sort((a, b) => a.products_name < b.products_name)
Descending
productarray.sort((a, b) => b.products_name < a.products_name),
You can reset the state of array you have passed as data in Flatlist
ascending ->
setProductSortList(
productarray.sort((a, b) => a.products_name < b.products_name),
);
do same for descending

NSPredicate filtering over array of complex objects

So, basically, the problem is, I have an object, let's call it "Product"
struct Product {
let categories: [Category]
}
And Category looks like this:
struct Category {
let id: Int
}
What I need, is to create NSPredicate, that would check if categories list contains Category of certain id. Now sure if it's possible, but maybe there's better workaround than creating another property with simple Int array?
Update: NSPredicate is mandatory because I need to use it in Realm database filter query.
The correct format for your NSPredicate would be:
let predicate = NSPredicate(format: "ANY categories.id == %#", argumentArray: [1])
The above example would return all Products whose categories array contains a Product with the id 1.
Of course, that's assuming that you're only looking for categories of a single id. If you needed to check for multiple ids, you could modify the above with an OR.
Note: I tested the above predicate with an NSArray, not Realm. However, if you check the Realm predicate cheatsheet, it does support all of the operators the predicate is using:
https://academy.realm.io/posts/nspredicate-cheatsheet/?_ga=2.32752254.1161432538.1537175891-1199086799.1527592477
If you are using Swift you can use filter and contains method to filter arrays.
When you have an array with products you can filter it by:
let filteredProducts = products.filter{ $0.categories.contains(where: { $0.id == 1 })}
The code above filters the products that contains a category with id = 1
You can simply check for the counts of the array returned by filter the categories.
struct Product {
let categories: [Category]
}
struct Category {
let id: Int
}
let c1 = Category(id: 1)
let c2 = Category(id: 2)
let c3 = Category(id: 3)
let p = Product(categories: [c1, c2, c3])
let yourCategoryId = 1
let filteredResults = p.categories.filter {
$0.id == yourCategoryId
}
let isCategoryWithIdPresent = filteredResults.count > 0 ? true : false
print(isCategoryWithIdPresent)
Hope it helps

Get 'data-sort' orthogonal value from DataTables within search.push function

I am looping the rows within $.fn.dataTable.ext.search.push function to select some rows based on many criteria. I am setting some values on the TD of the tables known as orthogonal data. I am trying to get the value of the 'data-sort' but I don't know how. I am able to get the cell's inner data via data[2] (for column 2), but not the 'data-sort' or 'data-filter'. Any ideas?
$.fn.dataTable.ext.search.push(
function (settings, data, dataIndex) {
var iRating = parseFloat(data[2]) || 0; // this works
var datasort = //somehow get the data-sort from the TD
);
HTML
<td data-sort="57000" class=" seqNum">.....</td>
Looks like this way I can get the value. If there are any other better ways please advice:
$(settings.aoData[dataIndex].anCells[2]).data('sort')
Yes there is an easier way.
The data parameter is the "search data" for the row. i.e. the values for "filter" data for each col - not your "sort" data / anything else.
But you also have access to the full data object for the row i.e. the 4th parameter - rowData.
So you need to use rowData at the index of the column you want (you say 'for column 2', zero based so - 2 would be for the 3rd column).
Then you should find a property called 'sort' :
function(settings, searchData, index, rowData, counter){
var dataSort = rowData[1]['sort'];
console.log(`This should be the value you want : ${dataSort}`);
}
As per the documentation here

Grails: "where" query with optional associations

I'm trying to run a "where" query to find a domain model object that has no association with another domain model object or if it does, that domain model object has a specific property value. Here's my code:
query = Model.where({
other == null || other.something == value
})
def list = query.list()
However, the resulting list only contains objects that match the second part of the OR statement. It contains no results that match the "other == null" part. My guess is that since it's checking a value in the associated object its forcing it to only check entries that actually have this associated object. If that is the case, how do I go about creating this query and actually having it work correctly?
You have to use a LEFT JOIN in order to look for null associations. By default Grails uses inner join which will not be joined for null results. Using withCriteria as below you should get the expected results:
import org.hibernate.criterion.CriteriaSpecification
def results = Model.withCriteria {
other(CriteriaSpecification.LEFT_JOIN){
or{
isNull 'id'
eq 'something', value
}
}
}
UPDATE
I know aliasing is not possible in DetachedCritieria where one would try to specify the join as in createCriteria/withCriteria. There is an existing defect regarding adding the functionality to DetachedCriteria. Just adding the work around for where query as mentioned in defect.
Model.where {
other {
id == null || something == value
}
}.withPopulatedQuery(null, null){ query ->
query.#criteria.subcriteriaList[0].joinType = CriteriaSpecification.LEFT_JOIN
query.list()
}
I would rather use withCriteria instead of the above hack.
this might work:
query = Model.where({
isNull( other ) || other.something == value
})
If that wouldn't work, try something like:
other.id == null || other.something == value
UPDATE:
or with good'ol criteria query:
list = Pack.withCriteria{
or{
isNull 'other'
other{ eq 'something', value }
}
}