Unable to add key value pairs in Javascript dictionary - javascript

I have some REACT code that generates a dictionary for me
My sample code is
var dict = []; // create an empty array
dict.push({
key: "keyName",
value: "the value"
});
and my dictionary looks like this
{key: "2021-03-31", value: 1}
{key: "2021-03-26", value: 1}
{key: "2021-03-27", value: 1}
{key: "2021-03-26", value: 1}
{key: "2021-03-27", value: 1}
Now I am trying to implement a logic like this.
If a key exists in the dictionary then I want to increase the number in the value by 1, or else insert a new key-value pair in the dictionary
var xkey=<<some value>>
if (xkey in dict) {
console.log("key found");
dt[xkey] +=1
}
else
{
dict.push(
{key: xkey
,value: 1 })
}
My If the condition is always failing and the code gets into the else block every time, hence the values for all keys are set to 1 whereas, in my example here, two of the keys should have had the value equal to 2.
My dictionary should have become
{key: "2021-03-31", value: 1}
{key: "2021-03-26", value: 2}
{key: "2021-03-27", value: 2}
Can someone please help me understand what I am doing wrong here?

You used Arrays and Objects in a mixed way. You can not acces an array elements by a key like you did. In other words you declared an Array not a Dictionory (called an Object in Javascript). The in operator only works aa s real members of the object dict.
Try this example:
var dict = {}; // create a map / object
...
var xkey=<<some key>>;
if (xkey in dict)
{
console.log("key found");
dict[xkey] +=1
}
else
{
dict[xkey] = 1;
}
There is also a shorter way.
var dict = {}; // create a map / object
...
var xkey=<<some key>>;
dict[xkey] = (xkey in dict) ? dict[xkey] + 1 : 1;
BTW your code is not compilable.

dict is an array and you probably want to find a specific date by key of a specific object in the dict array for modifying it's value . For finding your specific object in the array you can use simple find() method
let array = [
{ key: "2021-03-31", value: 1 },
{ key: "2021-03-26", value: 1 },
{ key: "2021-03-27", value: 1 },
]
const myKey = '2021-03-26'
let goalObject = array.find(object => object.key === myKey)
goalObject ? goalObject.value++ : array.push({ key: myKey, value: 1 })

You are trying to traverse to all records or else you can find an index and increase the value if the key is present. I have one solution maybe this will helps you to get your answer.
var dict = [];
function createDict(keyval) {
if (dict.length === 0) {
dict.push({
key: keyval,
value: 1
})
} else {
const index = dict.findIndex(x => x.key === keyval);
if (index > -1) {
dict[index].value += 1;
} else {
dict.push({
key: keyval,
value: 1
})
}
}
}
createDict("2021-03-31");
createDict("2021-03-26");
createDict("2021-03-27");
createDict("2021-03-26");
createDict("2021-03-27");
console.log(dict);
Final Results get like you want
[
{ key: '2021-03-31', value: 1 },
{ key: '2021-03-26', value: 2 },
{ key: '2021-03-27', value: 2 }
]

if (xkey in dict)
This is the problem. here dict is an array. So if you will check that x in dict it will look at the keys of an array.
In JavaScript arrays are just type of objects with keys that goes from 0 to length of the array and one extra key is length.
Let's see in your example:
your dict is like this:
dict = [
{key: "2021-03-31", value: 1},
{key: "2021-03-26", value: 1},
{key: "2021-03-27", value: 1},
{key: "2021-03-26", value: 1},
]
So if you run
for(xkey in dict){
console.log(xkey);
}
you will get output like this.
0
1
2
3
length
So if you check that "1" in dict then it will return true.
Solution to your problem might be look like this.
func addValue(newValue){ // newValue is value to add if does not exist and increment if exists
var isExist = false;
for(var i = 0; i < dict.length; i++){
if(dict[i].key === newValue){
dict[i].value++;
isExist = true;
break;
}
}
if(!isExist){
dict.push({key: newValue, value: 1})
}
}
More optimized solution is posted already by #Bhushi-da. This is for better understanding.

Related

How can I reduce elements in object?

I have an object like this:
result:
> rows:
> 0: {key: Array(4), value: 3}
> key: (4) ["Person", "2020-06-24", "Product, "00000000008"]
value: 3
> 1: {key: Array(4), value: 10}
> key: (4) ["Person", "2020-06-25", "Product, "00000000009"]
value: 10
> 2: {key: Array(4), value: 10}
> key: (4) ["Person", "2020-06-25", "Product, "00000000008"]
value: 10
Now, what I need to do is to reduce this result checking for the same code (for example 00000000008) and sum the value, to obtain:
(for example)
00000000008 value: 13
Now, my problem is how to do, I have tried to use first a map and then a reduce, but I don't understand how can I check for the same code and sum the value.
How can I do?
I have tried in this way, but it doesn't work:
res is the object with the values
let example = res.rows.map((element)=> {
console.log("ELEMENT IS ", element)
let example1 = element.key[3].reduce(function(element, v){
if(ref.hasOwnProperty(v))
element[ref[v]] += v;
else {
ref[v] = element.length;
element.push(prev = v)
}
return element
}, [])
})
console.log("element", element)
The Array.map method is useful for data transformations, but if you have to aggregate is mostly expensive because you have also to Array.filter the non-aggregated values.
You can use Array.reduce (MDN) instead in order to build your own object:
let result = {
rows: [
{
key: ["Person", "2020-06-24", "Product", "00000000008"],
value: 3
},
{
key: ["Person", "2020-06-25", "Product", "00000000009"],
value: 10
},
{
key: ["Person", "2020-06-25", "Product", "00000000008"],
value: 10
}
]
}
let output1 = result.rows.reduce((acc, current) => {
let key = current.key[3];
// adding value to the accumulator
acc[key] = (acc[key] || 0) + current.value;
return acc;
}, {});
console.log(output1);
let output2 = result.rows.reduce((acc, current) => {
// check if key is already present
let found = acc.find(v => v.key == current.key[3])
// if it is, update the current value
if (found) {
found.value += current.value;
}
// otherwise create a new one
else {
acc.push({ key: current.key[3], value: current.value });
}
return acc;
}, []);
console.log(output2)
create your own hashmap and loop over the result object once for all values
const hashmap = {};
rows.forEach(v => {
hashmap[v.product] = (hashmap[v.product] || 0) + v.value;
});
// then are you able to access any product value on O(1)
const total = hashmap['00000000008'];
console.log({total});
// total: 13

how to loop through an array of objects on reactjs then remove objects based on criteria [duplicate]

This question already has answers here:
javascript - remove array element on condition
(11 answers)
Closed 2 years ago.
I am using reactjs have the following data below and I want to loop through the array then if key === "oneline" or key === "twoline" remove the entire object.
In this example after removing the two objects (transformation), based on the description above it will only return objects with 0 and 3 inside the array.
const data = [
{0: {key: "zeroline", door: "zero"}},
{1: {key: "oneline", door: "one"}},
{2: {key: "twoline", door: "two"}},
{3: {key: "threeline", door: "three"}},
]
Any help would be very helpful.
Use Array filter method. The filter() method creates an array filled with all array elements that pass a test. The syntax of Array filter: array.filter(function(currentValue, index, arr), thisValue)
const data = [
{ 0: { key: "zeroline", door: "zero" } },
{ 1: { key: "oneline", door: "one" } },
{ 2: { key: "twoline", door: "two" } },
{ 3: { key: "threeline", door: "three" } },
];
let ret = data.filter((x, i) => x[i].key !== "oneline" && x[i].key !== "twoline");
console.log(ret);
You could filter it out with Array#filter.
const keywords = ['twoline', 'oneline'], data = [{0: {key: "zeroline", door: "zero"}},{1: {key: "oneline", door: "one"}},{2: {key: "twoline", door: "two"}},{3: {key: "threeline", door: "three"}}];
const res = data.filter((v, i) => keywords.indexOf(v[i].key) === -1);
console.log(res);
One way of doing it is:
const result = Object.keys(data).reduce((filtered,key,index) => {
//Getting specific object of array
//Example for first: data[0]["0"] === {key: "zeroline",door "zero"}
const object = data[index][key];
//Check if object key is zeroline or twoline
if(object.key === "zeroline" || object.key === "twoline"){
//If it is we push object to array
filtered.push(object)
}
return filtered
},[])

Remove Object From Array if the value is empty in name and value pair js

[{name: "mode", value: "1"},{name: "group", value: ""},{name: "from_date", value: ""},{name: "to_date", value: "2018-10-16"},{name: "action", value: "ac_filter_transactions"}
This is how my array looks like. I want to remove the name and value pair from the array if the value is empty.
I tried this solution: but this didn't work
formData.map((i) => {
(i.value == "") ? delete i: "";
});
I know this is a simple question but I couldn't find any relevant example to solve this problem. All examples and solutions I found was for this type of object
let obj = {"firstname": "XYZ", "lastname": "ABC"}
What are the difference between both the objects?
You can use Array.prototype.filter and return entries based on a boolean of whether or not the value exists since an empty string is falsy.
a.filter(o => (o.value));
let a = [{name: "mode", value: "1"},{name: "group", value: ""},{name: "from_date", value: ""},{name: "to_date", value: "2018-10-16"},{name: "action", value: "ac_filter_transactions"}];
let result = a.filter(o => (o.value));
console.log(result);
Note: If the any of your value properties are also falsy, they won't be picked up either. To get around this you could simply rewrite it using: (o.value !== "")
let a = [{name: "mode", value: "1"},{name: "group", value: ""},{name: "from_date", value: ""},{name: "to_date", value: "2018-10-16"},{name: "action", value: "ac_filter_transactions"}];
let result = a.filter(o => (o.value !== ""));
console.log(result);
For your question title I assume "remove" means mutate the array (change its actual content). If it is so you can do it like this:
const copy = arr.slice(); // copy of array for iterating without getting the index (`i`) wrong
let count = 0;
copy.forEach((val, i) => { if (!val.value) arr.splice(i - count++, 1); });
// maybe `val.value != ""` instead of `!val.value` ?
Demo:
var arr = [{name: "mode",value: "1"}, {name: "group", value: ""}, {name: "from_date",value: ""}, {name: "to_date", value: "2018-10-16"}, {name: "action",value:"ac_filter_transactions"}];
const copy = arr.slice();
let count = 0;
copy.forEach((val, i) => { if (!val.value) arr.splice(i - count++, 1); });
console.log(arr); // print original array, not a copy
Or if you do not want to mutate the array (do not change its actual content) then you can just make a (filtered) copy of it like this:
const copy = arr.filter(val => !!val.value)
Demo:
var arr = [{name: "mode",value: "1"}, {name: "group", value: ""}, {name: "from_date",value: ""}, {name: "to_date", value: "2018-10-16"}, {name: "action",value:"ac_filter_transactions"}];
console.log(arr.filter(val => !!val.value)); // print a copy, not the original array
Array.map will return the same number of items in a new array. So, you would need to use Array.reduce instead.
formData.reduce((result, item) => {
if (item.value) {
result.push(item);
}
return result;
}, []);

Check field in obj

Good day.
I've got
array a = [
{a:1, value: 2},
{a:2, value: 2},
{a:3, value: 2}
]
How I can check if all objects got same value return true if in one object I got different value return false.
Another option is using new Set() to get all the unique values. If the unique value is only one, it means all values are the same.
let a = [{a:1, value: 2},{a:2, value: 2},{a:3, value: 2}];
let result = [...new Set(a.map(o => o.value))].length === 1;
console.log(result);
To reduce overhead, as per suggested by Nina, you can:
let a = [{a:1, value: 2},{a:2, value: 2},{a:3, value: 2}];
let result = new Set(a.map(o => o.value)).size === 1;
console.log(result);
Just check the first value against all others.
var array = [{ a: 1, value: 2 }, { a: 2, value: 2 }, { a: 3, value: 2 }],
result = array.every(({ value }, _, a) => a[0].value === value);
console.log(result);
There is build int function every. You pass a predicate into it and if every item satisfied predicate - returns true, else - false.
const arr = [{a:1, value: 2},{a:2, value: 2},{a:3, value: 2}];
const result = arr.every(item => item.value === 2);
console.log(result);
You can also use simple logic using for to know if the value matches or not. Also, create a reusable function isMatch(arr) so that it can be reused for multiple array having same structure.
function isMatch(arr){
var val = arr[0].value;
var match = true;
for(var i=1; i<arr.length; i++){
if(val !== arr[i].value){
match = false;
break;
}
}
return match;
}
var a = [{a:1, value: 2},{a:2, value: 2},{a:3, value: 2}];
console.log(isMatch(a));
a = [{a:1, value: 2},{a:2, value: 3},{a:3, value: 2}];
console.log(isMatch(a));
People recommend using every, but I would recommend using some : every iterates over all items of the array, while some stops at the item when the predicate is false. In your example, this doesn't change much, but on large sets, it can improve performances.
try something like this :
const arr = [{a:1, value: 2}, {a:2, value: 2}, {a:3, value: 2}];
const value = arr[0].value;
const areEqual = arr.some(arrItem => arrItem.value === value);
console.log('are all equal : ', areEqual);
For my question help this answer
var answer = new Set(a.map(({value}) => value)).size === 1;

retriving values from javascript object and then convert it to one object

I have a problem! I am creating an rating app, and I have come across a problem that I don't know how to solve. The app is react native based so I am using JavaScript.
The problem is that I have multiple objects that are almost the same, I want to take out the average value from the values of the "same" objects and create a new one with the average value as the new value of the newly created object
This array in my code comes as a parameter to a function
var arr = [
{"name":"foo","value":2},
{"name":"foo","value":5},
{"name":"foo","value":2},
{"name":"bar","value":2},
{"name":"bar","value":1}
]
and the result I want is
var newArr = [
{"name":"foo","value":3},
{"name":"bar","value":1.5},
]
If anyone can help me I would appreciate that so much!
this is not my exact code of course so that others can take help from this as well, if you want my code to help me I can send it if that's needed
If you have any questions I'm more than happy to answer those
Iterate the array with Array.reduce(), and collect to object using the name values as the key. Sum the Value attribute of each name to total, and increment count.
Convert the object back to array using Object.values(). Iterate the new array with Array.map(), and get the average value by dividing the total by count:
const arr = [{"name":"foo","Value":2},{"name":"foo","Value":5},{"name":"foo","Value":2},{"name":"bar","Value":2},{"name":"bar","Value":1}];
const result = Object.values(arr.reduce((r, { name, Value }) => {
if(!r[name]) r[name] = { name, total: 0, count: 0 };
r[name].total += Value;
r[name].count += 1;
return r;
}, Object.create(null)))
.map(({ name, total, count }) => ({
name,
value: total / count
}));
console.log(result);
I guess you need something like this :
let arr = [
{name: "foo", Value: 2},
{name: "foo", Value: 5},
{name: "foo", Value: 2},
{name: "bar", Value: 2},
{name: "bar", Value: 1}
];
let tempArr = [];
arr.map((e, i) => {
tempArr[e.name] = tempArr[e.name] || [];
tempArr[e.name].push(e.Value);
});
var newArr = [];
$.each(Object.keys(tempArr), (i, e) => {
let sum = tempArr[e].reduce((pv, cv) => pv+cv, 0);
newArr.push({name: e, value: sum/tempArr[e].length});
});
console.log(newArr);
Good luck !
If you have the option of using underscore.js, the problem becomes simple:
group the objects in arr by name
for each group calculate the average of items by reducing to the sum of their values and dividing by group length
map each group to a single object containing the name and the average
var arr = [
obj = {
name: "foo",
Value: 2
},
obj = {
name: "foo",
Value: 5
},
obj = {
name: "foo",
Value: 2
},
obj = {
name: "bar",
Value: 2
},
obj = {
name: "bar",
Value: 1
}
]
// chain the sequence of operations
var result = _.chain(arr)
// group the array by name
.groupBy('name')
// process each group
.map(function(group, name) {
// calculate the average of items in the group
var avg = (group.length > 0) ? _.reduce(group, function(sum, item) { return sum + item.Value }, 0) / group.length : 0;
return {
name: name,
value: avg
}
})
.value();
console.log(result);
<script src="http://underscorejs.org/underscore-min.js"></script>
In arr you have the property Value and in newArr you have the property value, so I‘ll assume it to be value both. Please change if wished otherwise.
var map = {};
for(i = 0; i < arr.length; i++)
{
if(typeof map[arr[i].name] == ‘undefined‘)
{
map[arr[i].name] = {
name: arr[i].name,
value: arr[i].value,
count: 1,
};
} else {
map[arr[i].name].value += arr[i].value;
map[arr[i].name].count++;
}
var newArr = [];
for(prop in map)
{
map[prop].value /= map[prop].count;
newArr.push({
name: prop,
value: map[prop].value
});
}
delete map;

Categories