Related
so I want to find unique values from an array.
so for example I have this array:
const mainArr = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884']
so I want to find the first matching value for each unique item.
for example, in the array, I have two strings with the shape prefix, six items with the size prefix, and two items with the height prefix.
so I want to output to be something like
const requiredVal = ["shape-10983", "size-2364", "height-3399"]
I want only the first value from any set of different values.
the simplest solution will be to iterate on the list and storing what you got in a dictionary
function removeSimilars(input) {
let values = {};
for (let value of input) {//iterate on the array
let key = value.splitOnLast('-')[0];//get the prefix
if (!(key in values))//if we haven't encounter the prefix yet
values[key] = value;//store that the first encounter with the prefix is with 'value'
}
return Object.values(values);//return all the values of the map 'values'
}
a shorter version will be this:
function removeSimilars(input) {
let values = {};
for (let value of input)
values[value.splitOnLast('-')[0]] ??= value;
return Object.values(values);
}
You could split the string and get the type and use it aks key for an object along with the original string as value. At result take only the values from the object.
const
data = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884'],
result = Object.values(data.reduce((r, s) => {
const [type] = s.split('-', 1);
r[type] ??= s;
return r;
}, {}));
console.log(result);
If, as you mentioned in the comments, you have the list of prefixes already available, then all you have to do is iterate over those, to find each first element that starts with that prefix in your full list of possible values:
const prefixes = ['shape', 'size', 'height'];
const list = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884']
function reduceTheOptions(list = [], prefixes = [], uniques = []) {
prefixes.forEach(prefix =>
uniques.push(
list.find(e => e.startsWith(prefix))
)
);
return uniques;
}
console.log(reduceTheOptions(list, prefixes));
Try this:
function getRandomSet(arr, ...prefix)
{
// the final values are load into the array result variable
result = [];
const randomItem = (array) => array[Math.floor(Math.random() * array.length)];
prefix.forEach((pre) => {
result.push(randomItem(arr.filter((par) => String(par).startsWith(pre))));
});
return result;
}
const mainArr = ['shape-10983', 'size-2364', 'size-7800', 'size-4602', 'shape-11073', 'size-15027', 'size-15030', 'size-15033', 'height-3399', 'height-5884'];
console.log("Random values: ", getRandomSet(mainArr, "shape", "size", "height"));
I modified the #ofek 's answer a bit. cuz for some reason the ??= is not working in react project.
function removeSimilars(input) {
let values = {};
for (let value of input)
if (!values[value.split("-")[0]]) {
values[value.split("-")[0]] = value;
}
return Object.values(values);
}
create a new array and loop over the first array and check the existing of element before in each iteration if not push it to the new array
Problem
I would like to have the below two JSON combined together using the ID and have the expected result as mentioned below. I have tried a few solutions that were available but none worked for my use case. Any suggestions will be great !!
Tried to do:
How to merge two json object values by id with plain Javascript (ES6)
Code
var json1 = [
{
"id":"A123",
"cost":"5020.67",
"fruitName":"grapes"
},
{
"id":"A456",
"cost":"341.30",
"fruitName":"apple"
},
{
"id":"A789",
"cost":"3423.04",
"fruitName":"banana"
}
];
var json2 = [
{
"id":"A123",
"quantity":"7"
},
{
"id":"A789",
"quantity":"10"
},
{
"id":"ABCD",
"quantity":"22"
}
];
Below is the code I tried:
var finalResult = [...[json1, json2].reduce((m, a) => (a.forEach(o => m.has(o.id) && Object.assign(m.get(o.id), o) || m.set(o.id, o)), m), new Map).values()];
Expected result:
[
{
"id":"A123",
"cost":"5020.67",
"fruitName":"grapes",
"quantity":"7"
},
{
"id":"A456",
"cost":"341.30",
"fruitName":"apple"
},
{
"id":"A789",
"cost":"3423.04",
"fruitName":"banana",
"quantity":"10"
},
{
"id":"ABCD",
"quantity":"22"
}
]
You can accomplish this fairly easily without getting too fancy. Here's the algorithm:
Put the items from json1 into an object by id, so that you can look them up quickly.
For each item in json2: If it already exists, merge it with the existing item. Else, add it to objectsById.
Convert objectsById back to an array. I've used Object.values, but you can also do this easily with a loop.
var json1 = [
{
"id":"A123",
"cost":"5020.67",
"fruitName":"grapes"
}, {
"id":"A456",
"cost":"341.30",
"fruitName":"apple"
}, {
"id":"A789",
"cost":"3423.04",
"fruitName":"banana"
}
];
var json2 = [
{
"id":"A123",
"quantity":"7"
}, {
"id":"A789",
"quantity":"10"
}
];
const objectsById = {};
// Store json1 objects by id.
for (const obj1 of json1) {
objectsById[obj1.id] = obj1;
}
for (const obj2 of json2) {
const id = obj2.id;
if (objectsById[id]) {
// Object already exists, need to merge.
// Using lodash's merge because it works for deep properties, unlike object.assign.
objectsById[id] = _.merge(objectsById[id], obj2)
} else {
// Object doesn't exist in merged, add it.
objectsById[id] = obj2;
}
}
// All objects have been merged or added. Convert our map to an array.
const mergedArray = Object.values(objectsById);
I think a few steps are being skipped in your reduce function. And it was a little difficult to read because so many steps are being combined in one.
One critical piece that your function does not account for is that when you add 2 numerical strings together, it concats the strings.
const stringTotal = "5020.67" + "3423.04" // result will be "5020.673423.04"
The following functions should give you the result you are looking for.
// calculating the total cost
// default values handles cases where there is no obj in array 2 with the same id as the obj compared in array1
const calcualteStringTotal = (value1 = 0, value2 = 0) => {
const total = parseFloat(value1) + parseFloat(value2)
return `${total}`
}
const calculateTotalById = (array1, array2) => {
const result = []
// looping through initial array
array1.forEach(outterJSON => {
// placeholder json obj - helpful in case we have multiple json in array2 with the same id
let combinedJSON = outterJSON;
// looping through second array
array2.forEach(innerJSON => {
// checking ids
if(innerJSON.id === combinedJSON.id) {
// calls our helper function to calculate cost
const updatedCost = calcualteStringTotal(innerJSON.cost, outterJSON.cost)
// updating other properties
combinedJSON = {
...outterJSON,
...innerJSON,
cost: updatedCost
}
}
})
result.push(combinedJSON)
})
return result
}
const combinedResult = calculateTotalById(json1, json2)
I figured that by using reduce I could make it work.
var finalResult = [...[json1, json2].reduce((m, a) => (a.forEach(o => m.has(o.id) && Object.assign(m.get(o.id), o) || m.set(o.id, o)), m), new Map).values()];
I have the following json:
{0: "2", 1: "2", $$hashKey: "object:35", undefined: "1"}
Currently I am trying to get its key-value with the below code:
var data = JSON.stringify(row);
var result = $.parseJSON(data);
$.each(result, function (k, v) {
//display the key and value pair
console.log(k, v);
});
The above code works fine and I can get my key-value from it.
Now what I am trying to get is the next key-value pairs within the $.each loop.
For example if in the loop the current key is "0" I want to get the next key "1" in the same call itself. If in the loop the current key is "1" I want to get the next key "$$hashKey" along with their values.
Is it possible to do so? I am open to code changes above if required.
You can use Object.keys to get the keys to an array, then run through it with a forEach to have access to the keys index. Important to note that objects are unordered, so your key order one time may differ from the next time:
var keys = Object.keys(obj);
keys.forEach(function(key, index) {
var nextIndex = index + 1;
if (nextIndex === keys.length) return; //out of bounds
var nextKey = keys[nextIndex];
});
Edit: As pointed out by the comments - if you want the keys in the same order each time, call .sort() on your keys array with your desired sort logic.
Understanding now that the goal is to retrieve keys in the order they appear in JSON, a couple of thoughts:
(1) if you control the source of the object ("row" in the OP code), don't represent it as an object. instead use an array of key-value pairs: [[0, "2"], [1, "2"], [$$hashKey, "object:35"], [undefined, "1"]].
otherwise, (2) roll your own JSON parser that returns an array of key-value pairs for an object. This post looks to be a sensible start. Or, you can vastly simplify the task if you are able to make certain assumptions about the values, for example, say you know that all values are strings...
// parse a string representing an object, returning an array of key-value pairs.
// assumes values are strings that do not contain commas or colons
function myProbablyNegligentlySimpleJSONParse(string) {
let trimmed = string.trim().slice(1, -1);
let components = trimmed.split(',');
return components.map(kvString => {
let kv = kvString.split(':');
return [ kv[0].trim(), kv[1].trim() ];
});
}
forEach passes the current index to the iterator function, so that int can be used to look ahead or behind in the iteration.
var data = '{0: "2", 1: "2", $$hashKey: "object:35", undefined: "1"}';
let result = myProbablyNegligentlySimpleJSONParse(data);
result.forEach(function (pair, index) {
let [k, v] = pair; // now k and v are your key and value
console.log(`key is ${k} value is ${v}`)
if (index < result.length-1) {
let [nextK, nextV] = result[index+1];
console.log(`next key is ${nextK} next value is ${nextV}`);
}
});
You could turn your object into an iterable and which will return the next [key, value] pair each time you call next on the iterator:
function makeIterable(o) {
o[Symbol.iterator] = () => {
var keys = Object.keys(o);
var i = 0;
return {
next() {
var done = false;
var value = [keys[i + 1], o[keys[i + 1]]];
if (i >= (keys.length - 1)) {
done = true;
}
i++;
return {
value,
done
}
}
};
}
}
var jsonStr = '{ "0": "2", "1": "2", "$$hashKey": "object:35", "undefined": "1" }';
var obj = JSON.parse(jsonStr);
makeIterable(obj);
var itr = obj[Symbol.iterator]();
while (true) {
var item = itr.next();
if (item.done) {
break;
}
console.log(item.value);
}
I am trying to use reduce() for getting economy rate for a particular wicket.
Example data:
var data = [
{wicket:0, econ:20 },
{wicket:1, econ:10 },
{wicket:3, econ:45 },
{wicket:0, econ:15 },
{wicket:1, econ:32 }
]
I want reduce() method to return an array of objects which will look like this:
0: 20, 15
1: 10, 32
3: 45
What I am trying to do is initialize accumulator with object but in reduce() method I am not able to figure out how can I get the required array of objects with key value as wicketand values as economy.
My code:
const Economy = data.reduce( (a, {econ, wicket}) => {
a[wicket].push(econ);
},{})
I get undefined behaviour with above code.
If your data was meant to be an Array and not an Object (which it isn't right now, at least not a valid one) :
let data = [
{wicket:0, econ:20 },
{wicket:1, econ:10 },
{wicket:3, econ:45 },
{wicket:0, econ:15 },
{wicket:1, econ:32 }
];
let result = data.reduce((acc, curr) => {
if(acc[curr.wicket]) acc[curr.wicket].push(curr.econ);
else acc[curr.wicket] = [curr.econ];
return acc;
},{});
console.log(result);
You can use group the array using reduce like:
var data = [{"wicket":0,"econ":20},{"wicket":1,"econ":10},{"wicket":3,"econ":45},{"wicket":0,"econ":15},{"wicket":1,"econ":32}];
var result = data.reduce((c, v) => {
c[v.wicket] = c[v.wicket] || []; //Initiate the property as empty array of it does not exist
c[v.wicket].push(v.econ);
return c;
}, {});
console.log(result);
|| is an OR operator.
This means if c[v.wicket] exist, it will assign it to c[v.wicket] again. If it does not, assign an empty array []
c[v.wicket] = c[v.wicket] || [];
I am trying to reduce a JSON array. Inside the array are other object, I am trying to turn the attributes into their own array.
Reduce Function:
// parsed.freight.items is path
var resultsReduce = parsed.freight.items.reduce(function(prevVal, currVal){
return prevVal += currVal.item
},[])
console.log(resultsReduce);
// two items from the array
// 7205 00000
console.log(Array.isArray(resultsReduce));
// false
The reduce function is kind of working. It gets both item from the items array. However I am having a couple problems.
1) The reduce is not passing back an array. See isArray test
2) I am trying to make a function so I can loop through all of the attributes in the array the qty, units, weight, paint_eligable. I cannot pass a variable to the currVal.variable here
Attempting:
var itemAttribute = 'item';
var resultsReduce = parsed.freight.items.reduce(function(prevVal, currVal){
// pass param here so I can loop through
// what I actually want to do it create a function and
// loop through array of attributes
return prevVal += currVal.itemAttribute
},[])
JSON:
var request = {
"operation":"rate_request",
"assembled":true,
"terms":true,
"subtotal":15000.00,
"shipping_total":300.00,
"taxtotal":20.00,
"allocated_credit":20,
"accessorials":
{
"lift_gate_required":true,
"residential_delivery":true,
"custbodylimited_access":false
},
"freight":
{
"items":
// array to reduce
[{
"item":"7205",
"qty":10,
"units":10,
"weight":"19.0000",
"paint_eligible":false
},
{ "item":"1111",
"qty":10,
"units":10,
"weight":"19.0000",
"paint_eligible":false
}],
"total_items_count":10,
"total_weight":190.0},
"from_data":
{
"city":"Raleigh",
"country":"US",
"zip":"27604"},
"to_data":
{
"city":"Chicago",
"country":"US",
"zip":"60605"
}
}
Thanks in advance
You may need Array#map for getting an array of items
var resultsReduce = parsed.freight.items.reduce(function (array, object) {
return array.concat(object.item);
}, []);
The same with a given key, with bracket notation as property accessor
object.property
object["property"]
var key = 'item',
resultsReduce = parsed.freight.items.reduce(function (array, object) {
return array.concat(object[key]);
}, []);