So, I have data. It is array of objects.
data = [
{
"id": "200",
"price": "5000"
},
{
"id": "137",
"price": "8000"
},
{
"id": "230",
"price": "9000"
},
{
"id": "241",
"price": "9000"
},
{
"id": "78",
"price": "10000"
}
]
json=JSON.parse(data);
I make something like pager.
My code should return nearby (previous and next) elements of original element.
It is not allowed to change order of objects.
I'm trying to do something like
json.indexOf(JSON.parse('{"id":"200","price":"5000"}'))
but it returns -1.
Also json[0]==JSON.parse('{"id":"200","price":"5000"}') return false, but I think that this elements are similar.
What way do you see?
json=JSON.parse('[{"id":"200","price":"5000"},{"id":"137","price":"8000"},{"id":"230","price":"9000"},{"id":"241","price":"9000"},{"id":"78","price":"10000"}]');
console.log(json.indexOf(JSON.parse('{"id":"200","price":"5000"}')));
console.log(json[0]==JSON.parse('{"id":"200","price":"5000"}'));
console.log(json[0]);
console.log(JSON.parse('{"id":"200","price":"5000"}'));
You could take a function which finds the index of the wanted id and returns items before that index, the index and one after the index with adjustment at the beginning of the array.
function getParts(id) {
var index = array.findIndex(o => o.id === id),
min = Math.max(index - 1, 0);
if (index !== -1) {
return array.slice(min, min + (index ? 3 : 2));
}
}
var array = JSON.parse('[{"id":"200","price":"5000"},{"id":"137","price":"8000"},{"id":"230","price":"9000"},{"id":"241","price":"9000"},{"id":"78","price":"10000"}]');
console.log(getParts('200'));
console.log(getParts('137'));
console.log(getParts('230'));
console.log(getParts('78'));
Try this, i think it would work as the 'id' property is unique
var words = [{"id":"200","price":"5000"},{"id":"137","price":"8000"},{"id":"230","price":"9000"},{"id":"241","price":"9000"},{"id":"78","price":"10000"}];
let k;
let sayYourKeyId = "137";
const result = words.find((word, index) => {
if(word.id == sayYourKeyId){
k = index;
}
});
console.log(words[k-1]);
console.log(words[k]);
console.log(words[k+1]);
Related
I have a set of checkboxes - which the user ticks on. The checkboxes pass some data an id and a name that i need later on for sorting. Because two objects are not equal even though they contain the same values I cant use Array.includes.
Here is an example of the data
[
{
"id": 9,
"name": "age_group_ids"
},
{
"id": 9,
"name": "age_group_ids"
},
{
"id": 9,
"name": "earnings_group_ids"
},
{
"id": 3,
"name": "earnings_group_ids"
},
]
This is the current function (which would work if the items were not objects
const submitFilterDetails = (value) => {
return async (dispatch,getState) => {
const currentArray = (getState().filter.filtersArray);
if(!currentArray.includes(value)) {
dispatch(addToFiltersArray(value))
} else {
dispatch(removeFromFiltersArray(value));
}
}
}
How can you sort this so I only have unique values
You can use find :
YourArray.find(obj => obj.id == value.id && obj.name == value.name);
const src = [
{
"id": 9,
"name": "age_group_ids"
},
{
"id": 9,
"name": "age_group_ids"
},
{
"id": 1,
"name": "earnings_group_ids"
},
]
const out = src.reduce((acc, curr) => acc.some(i => i.id === curr.id) ? acc : acc.concat([curr]) , [])
// the `out` variable has 2 unique items
Got an object containing a user id for each user and prices, would like to create a new object/array for each user (no duplicates) and be able to calculate the total sum of price for each user. Tried using Object.values() with map and filter but can't get it to work properly
{
"data": {
"item1": {
"price": "20",
"user": "user1"
},
"item2": {
"price": "10",
"user": "user2"
},
"item3": {
"price": "50",
"user": "user1"
}
}
}
Output something like this:
{
"users": {
"user1": {
"totalSum": "70",
},
"user2": {
"totalSum": "10",
}
}
}
I'm thinking about using map to present the "users"-data, maybe an array would be better?
Using function reduce.
Important: The attribute price is a String, this approach uses object Number to convert that value to a numeric one.
var obj = { "data": { "item1": { "price": "20", "user": "user1" }, "item2": { "price": "10", "user": "user2" }, "item3": { "price": "50", "user": "user1" } }};
var result = Object.keys(obj.data).reduce((a, k) => {
if (a.users[obj.data[k].user]) {
a.users[obj.data[k].user].totalSum += Number(obj.data[k].price);
} else {
a.users[obj.data[k].user] = {
"totalSum": Number(obj.data[k].price)
}
}
return a;
}, {
'users': {}
});
console.log(result);
.as-console-wrapper {
max-height: 100% !important; top: 0;
}
You could leverage ```reduce, more information here
code (haven't tried this)
var data = JSON.parse(mainObj).data;
var usersWithTotalExpenditure = Object.keys(data).reduce(function(result, key) {
var currentItem = data[key];
var useName = currentItem.user;
var price = Number(currentItem.price);
if (userName in result) {
result[userName].totalSum += price;
} else {
result[userName] = {
totalSum: price
};
}
return result;
}, {});
var resultObject = {
users: usersWithTotalExpenditure
}
You can use a forEach loop. This relies on Javascripts powerful OR operator, which coerces the first half of the expression to false if the current user's price is not defined (meaning it is a user the loop hasn't encountered before)
`c is your initial object's data, output is empty object`
const c = obj.data;
var output = {};
Object.keys(c).forEach((val) => {
output[c[val]["user"]] = parseInt(output[c[val]["user"]]) + parseInt(c[val]["price"]) || parseInt(c[val]["price"]);
})
I've got an array of three people. I want to add a new key to multiple objects at once based on an array of indices. Clearly my attempt at using multiple indices doesn't work but I can't seem to find the correct approach.
var array = [
{
"name": "Tom",
},
{
"name": "Dick",
},
{
"name": "Harry",
}
];
array[0,1].title = "Manager";
array[2].title = "Staff";
console.log(array);
Which returns this:
[
{
"name": "Tom",
},
{
"name": "Dick",
"title": "Manager"
},
{
"name": "Harry",
"title": "Staff"
}
]
But I'd like it to return this.
[
{
"name": "Tom",
"title": "Manager"
},
{
"name": "Dick",
"title": "Manager"
},
{
"name": "Harry",
"title": "Staff"
}
]
You cannot use multiple keys by using any separator in arrays.
Wrong: array[x, y]
Correct: array[x] and array[y]
In your case, it will be array[0].title = array[1].title = "manager";
1st method::
array[0].title = "Manager";
array[1].title = "Manager";
array[2].title = "Staff";
array[0,1] will not work.
2nd method::
for(var i=0;i<array.length;i++) {
var msg = "Manager";
if(i===2) {
msg = "Staff"
}
array[i].title = msg
}
You can use a helper function like this
function setMultiple(array, key, indexes, value)
{
for(i in array.length)
{
if(indexes.indexOf(i)>=0){
array[i][key] = value;
}
}
}
And then
setMultiple(array, "title", [0,1], "Manager");
Try this: `
for (var i=0; var<= array.length; i++){
array[i].title = "manager";
}`
Or you can change it around so var is less than or equal to any n range of keys in the index.
EDIT: instead make var <= 1. The point is to make for loops for the range of indices you want to change the title to.
Assuming that you have a bigger set of array objects.
var array = [
{
"name": "Tom",
},
{
"name": "Dick",
},
{
"name": "Harry",
},
.
.
.
];
Create an object for the new keys you want to add like so:
let newKeys = {
'Manager': [0,2],
'Staff': [1]
}
Now you can add more such titles here with the required indexes.
with that, you can do something like:
function addCustomProperty(array, newKeys, newProp) {
for (let key in newKeys) {
array.forEach((el, index) => {
if (key.indexOf(index) > -1) { // if the array corresponding to
el[newProp] = key // the key has the current array object
} // index, then add the key to the
}) // object.
}
return array
}
let someVar = addCustomProperty(array, newKeys, 'title')
I have an array of objects that I would like to trim down based on a specific key:value pair. I want to create an array that includes only one object per this specific key:value pair. It doesn't necessarily matter which object of the duplicates is copied to the new array.
For example, I want to trim based on the price property of arrayWithDuplicates, creating a new array that only includes one of each value:
var arrayWithDuplicates = [
{"color":"red",
"size": "small",
"custom": {
"inStock": true,
"price": 10
}
},
{"color":"green",
"size": "small",
"custom": {
"inStock": true,
"price": 30
}
},
{"color":"blue",
"size": "medium",
"custom": {
"inStock": true,
"price": 30
}
},
{"color":"red",
"size": "large",
"custom": {
"inStock": true,
"price": 20
}
}
];
Would become:
var trimmedArray = [
{"color":"red",
"size": "small",
"custom": {
"inStock": true,
"price": 10
}
},
{"color":"green",
"size": "small",
"custom": {
"inStock": true,
"price": 30
}
},
{"color":"red",
"size": "large",
"custom": {
"inStock": true,
"price": 20
}
}
];
Is there a JavaScript or Angular function that would loop through and do this?
EDIT: The property to filter on is nested within another property.
This function removes duplicate values from an array by returning a new one.
function removeDuplicatesBy(keyFn, array) {
var mySet = new Set();
return array.filter(function(x) {
var key = keyFn(x), isNew = !mySet.has(key);
if (isNew) mySet.add(key);
return isNew;
});
}
var values = [{color: "red"}, {color: "blue"}, {color: "red", number: 2}];
var withoutDuplicates = removeDuplicatesBy(x => x.color, values);
console.log(withoutDuplicates); // [{"color": "red"}, {"color": "blue"}]
So you could use it like
var arr = removeDuplicatesBy(x => x.custom.price, yourArrayWithDuplicates);
I don't think there's a built-in function in Angular, but it isn't hard to create one:
function removeDuplicates(originalArray, objKey) {
var trimmedArray = [];
var values = [];
var value;
for(var i = 0; i < originalArray.length; i++) {
value = originalArray[i][objKey];
if(values.indexOf(value) === -1) {
trimmedArray.push(originalArray[i]);
values.push(value);
}
}
return trimmedArray;
}
Usage:
removeDuplicates(arrayWithDuplicates, 'size');
Returns:
[
{
"color": "red",
"size": "small"
},
{
"color": "blue",
"size": "medium"
},
{
"color": "red",
"size": "large"
}
]
And
removeDuplicates(arrayWithDuplicates, 'color');
Returns:
[
{
"color": "red",
"size": "small"
},
{
"color": "green",
"size": "small"
},
{
"color": "blue",
"size": "medium"
}
]
Use Array.filter(), keeping track of values by using an Object as a hash, and filtering out any items whose value is already contained in the hash.
function trim(arr, key) {
var values = {};
return arr.filter(function(item){
var val = item[key];
var exists = values[val];
values[val] = true;
return !exists;
});
}
You can use underscore for this:
//by size:
var uSize = _.uniqBy(arrayWithDuplicates, function(p){ return p.size; });
//by custom.price;
var uPrice = _.uniqBy(arrayWithDuplicates, function(p){ return p.custom.price; });
You can use lodash to remove duplicate objects:
import * as _ from 'lodash';
_.uniqBy(data, 'id');
Here 'id' is your unique identifier
Try the following function:
function trim(items){
const ids = [];
return items.filter(item => ids.includes(item.id) ? false : ids.push(item.id));
}
using lodash you can filter it out easily
the first parameter will be your array and second will be your field with duplicates
_.uniqBy(arrayWithDuplicates, 'color')
it will return an array with unique value
Simple solution although not the most performant:
var unique = [];
duplicates.forEach(function(d) {
var found = false;
unique.forEach(function(u) {
if(u.key == d.key) {
found = true;
}
});
if(!found) {
unique.push(d);
}
});
for (let i = 0; i < arrayWithDuplicates.length; i++) {
for (let j = i + 1; j < arrayWithDuplicates.length; j++) {
if (arrayWithDuplicates[i].name === students[j].name) {
arrayWithDuplicates.splice(i, 1);
}
}
}
this will work perfectly...and this will delete first repeated array.
To delete last repeated array we only have to change
arrayWithDuplicates.splice(i, 1) ; into
arrayWithDuplicates.splice(j, 1);
Off the top of my head there is no one function that will do this for you as you are dealing with an array of objects and also there is no rule for which duplicate would be removed as duplicate.
In your example you remove the one with size: small but if you were to implement this using a loop you'd most likely include the first and exclude the last as you loop through your array.
It may very well be worth taking a look at a library such as lodash and creating a function that uses a combination of it's API methods to get the desired behaviour you want.
Here is a possible solution you could use making use of basic Arrays and a filter expression to check whether a new item would be considered a duplicate before being attached to a return result.
var arrayWithDuplicates = [
{"color":"red", "size": "small"},
{"color":"green", "size": "small"},
{"color":"blue", "size": "medium"},
{"color":"red", "size": "large"}
];
var reduce = function(arr, prop) {
var result = [],
filterVal,
filters,
filterByVal = function(n) {
if (n[prop] === filterVal) return true;
};
for (var i = 0; i < arr.length; i++) {
filterVal = arr[i][prop];
filters = result.filter(filterByVal);
if (filters.length === 0) result.push(arr[i]);
}
return result;
};
console.info(reduce(arrayWithDuplicates, 'color'));
You can check out some literature on Array filtering here
If you need to provide a preference on which item to remove you could define extra parameters and logic that will make extra property checks before adding to a return value.
Hope that helps!
Here is the typescript way
public removeDuplicates(originalArray:any[], prop) {
let newArray = [];
let lookupObject = {};
originalArray.forEach((item, index) => {
lookupObject[originalArray[index][prop]] = originalArray[index];
});
Object.keys(lookupObject).forEach(element => {
newArray.push(lookupObject[element]);
});
return newArray;
}
And
let output = this.removeDuplicates(yourArray,'color');
This is just another 'feature' based on yvesmancera's solution (after I started tinkering for my own solution) Also noted we are only allowed to currently use IE 11, so limited ES5 is allowed.
var newArray = RemoveDuplicates(myArray,'Role', 2);
function RemoveDuplicates(array, objKey, rtnType) {
var list = [], values = [], value;
for (var i = 0; i < array.length; i++) {
value = array[i][objKey];
if(values.indexOf(value) === -1){
list.push(array[i]);
values.push(value);
}
}
if(rtnType == 1)
return list;
return values;
};
Hoping this will work for most, if not all arrays when filtering out objects based on a single object property value.
I have a nested array like this:
array = [
{
"id": "67",
"sub": [
{
"id": "663",
},
{
"id": "435",
}
]
},
{
"id": "546",
"sub": [
{
"id": "23",
"sub": [
{
"id": "4",
}
]
},
{
"id": "71"
}
]
}
]
I need to find 1 nested object by its id and get all its parents, producing an array of ids.
find.array("71")
=> ["546", "71"]
find.array("4")
=> ["546", "23", "4"]
What's the cleanest way to do this? Thanks.
Recursively:
function find(array, id) {
if (typeof array != 'undefined') {
for (var i = 0; i < array.length; i++) {
if (array[i].id == id) return [id];
var a = find(array[i].sub, id);
if (a != null) {
a.unshift(array[i].id);
return a;
}
}
}
return null;
}
Usage:
var result = find(array, 4);
Demo: http://jsfiddle.net/Guffa/VBJqf/
Perhaps this - jsonselect.org.
EDIT: I've just had a play with JSONSelect and I don't think it's appropriate for your needs, as JSON does not have an intrinsic 'parent' property like xml.
It can find the object with the matching id, but you can't navigate upwards from that. E.g.
JSONSelect.match(':has(:root > .id:val("4"))', array)
returns me:
[Object { id="4"}]
which is good, it's just that I can't go anywhere from there!