Removing specific key-value pairs from a document/object - javascript

I have a document that looks like something like this:
{
name: "Johnny Boy",
age: 24,
hobbies: ["fencing", "chess", "raves"],
_createdAt: 2015-05-15T18:12:26.731Z,
_createdBy: "JohnnyBoy",
_id: mQW4G5yEfZtsB6pcN
}
My goal is to return everything that doesn't start with an underscore, and format it a bit differently so I will end up with this:
[
{
fieldName: "name",
value: "Johnny Boy"
},
{
fieldName: "age",
value: 24
},
{
fieldName: "hobbies",
value: ["fencing", "chess", "raves"]
}
]
My initial solution was to run it through the _.map function of the Underscore library (which has nothing to do with my wanting to remove underscores specifically...) and then using lastIndexOf to figure out which keys begin with an underscore:
var listWithoutUnderscores = _.map(myList, function(val, key) {
if (key.lastIndexOf("_", 0) === -1)
return {fieldName: key, value: val}
return null
})
However, this will literally return null instead of the fields that began with _ in the returned array:
[
...
{
fieldname: "hobbies",
value: ["fencing", "chess", "raves"]
},
null,
null,
null
]
I want to remove them completely, ideally within the map function itself, or else by chaining it through some kind of filter but I don't know which one is fastest in this case.

You can use reduce for this:
var listWithoutUnderscores = _.reduce(myList, function(list, val, key) {
if (key.lastIndexOf("_", 0) === -1){
list.push( {fieldName: key, value: val});
}
return list;
}, []);

Underscore also comes with an array method compact which will remove all falsey and null values from an array:
_.compact([0, 1, false, 2, '', null, 3]);
=> [1, 2, 3]
You could just call _.compact(array) on the array after your map.

You can use pick and pass a predicate to get the valid keys and then map across those fields:
var validKey = function(value, key){
return _.first(key) != '_';
}
var createField = function(value, key){
return {
fieldname: key,
value: value
}
}
var result = _.chain(data)
.pick(validKey)
.map(createField)
.value();
var data = {
name: "Johnny Boy",
age: 24,
hobbies: ["fencing", "chess", "raves"],
_createdAt: '2015-05-15T18:12:26.731Z',
_createdBy: "JohnnyBoy",
_id: 'mQW4G5yEfZtsB6pcN'
}
var validKey = function(value, key){
return _.first(key) != '_';
}
var createField = function(value, key){
return {
fieldname: key,
value: value
}
}
var result = _.chain(data)
.pick(validKey)
.map(createField)
.value();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>

Related

How to add a new key:value pair to an already existing array state variable react native

I have a database function that returns some rows from a sqlite database then stores that in state
rows = await ReturnSelectedSymbolsDB()
this.setState({ symbols: rows })
The array looks something like this
symbols: [{key: "0", symbol:"name1", active: false},{key:"1", symbol:"name2",active: false}]
I have another database function which returns some rows and I wish to add them to symbol so it would look like this.
symbols: [{key: "0", symbol:"name1", active: false, newKey: newValue},{key:"1", symbol:"name2",active: false, newKey, newValue2}]
The second function will return multiple rows from the database which will be easy to match up with symbols as symbols:symbol will match otherFunction:symbol.
Normally you would just write this like a regular SQL query with a inner join joining the 2 tables together and then just putting the resulting rows in a state variable but I cannot in this case and must build the state variable piece by piece.
Can this be done is regular javascript?
EDIT:
Probably wasnt clear but newKey can have different values depending on what the name of the symbol is
You can create a new util function where you can add new key to all object inside the array.
addKey(symbol) {
let newArray=[...symbol];
return newArray.map((ele, i) => {
return {...ele, newKey: newValue};
})
}
Happy Coding :)
You have to insert your new value into your first function array, there are couples of way can insert object in array either use for loop or array manipulation functions.
var arrOfObj = [{
key: "0",
symbol:"name1",
active: false
}, {
key: "1",
symbol:"name1",
active: false
}, {
key: "2",
symbol:"name1",
active: false
}];
var result = arrOfObj.map(function(o) {
o.newKey = newValue;
return o;
})
console.log(result)
Note: I would prefer to go with inner join with two tables to return
combine array that not require any array manipulation.
You could do something like this if you know the key value corresponding to a given symbol:
for (let i = 0; i < symbols.length; i++){
symbols[i].newKey = "anyValue"
}
Try this,
let symbols = [
{ key: "0", symbol: "name1", active: false },
{ key: "1", symbol: "name2", active: false }
];
let newSymbols = [
{ key: "1", symbol: "name1", newKey: "fdds" },
{ key: "0", symbol: "name2", newKey: "sadav" }
];
mergeArray = (arrayOld, arrayNew) => {
let output = arrayOld.filter(item => {
let find = findMatchingItem(arrayNew, item.key);
item["newKey"] = find.newKey;
return item;
});
return output;
};
findMatchingItem = (array, matchingItemKey) => {
let output = null;
array.map(item => {
if (item.key == matchingItemKey) {
output = item;
}
});
return output;
};
let newArray = mergeArray(symbols, newSymbols);
console.log(newArray);
I have matched objects using "key" if you want from "symbol" just change "key" to "symbol"

How to add non duplicate objects in an array in javascript?

I want to add non-duplicate objects into a new array.
var array = [
{
id: 1,
label: 'one'
},
{
id: 1,
label: 'one'
},
{
id: 2,
label: 'two'
}
];
var uniqueProducts = array.filter(function(elem, i, array) {
return array.indexOf(elem) === i;
});
console.log('uniqueProducts', uniqueProducts);
// output: [object, object, object]
live code
I like the class based approach using es6. The example uses lodash's _.isEqual method to determine equality of objects.
var array = [{
id: 1,
label: 'one'
}, {
id: 1,
label: 'one'
}, {
id: 2,
label: 'two'
}];
class UniqueArray extends Array {
constructor(array) {
super();
array.forEach(a => {
if (! this.find(v => _.isEqual(v, a))) this.push(a);
});
}
}
var unique = new UniqueArray(array);
console.log(unique);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
Usually, you use an object to keep track of your unique keys. Then, you convert the object to an array of all property values.
It's best to include a unique id-like property that you can use as an identifier. If you don't have one, you need to generate it yourself using JSON.stringify or a custom method. Stringifying your object will have a downside: the order of the keys does not have to be consistent.
You could create an objectsAreEqual method with support for deep comparison, but this will slow your function down immensely.
In two steps:
var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];
// Create a string representation of your object
function getHash(obj) {
return Object.keys(obj)
.sort() // Keys don't have to be sorted, do it manually here
.map(function(k) {
return k + "_" + obj[k]; // Prefix key name so {a: 1} != {b: 1}
})
.join("_"); // separate key-value-pairs by a _
}
function getHashBetterSolution(obj) {
return obj.id; // Include unique ID in object and use that
};
// When using `getHashBetterSolution`:
// { '1': { id: '1', label: 'one' }, '2': /*etc.*/ }
var uniquesObj = array.reduce(function(res, cur) {
res[getHash(cur)] = cur;
return res;
}, {});
// Convert back to array by looping over all keys
var uniquesArr = Object.keys(uniquesObj).map(function(k) {
return uniquesObj[k];
});
console.log(uniquesArr);
// To show the hashes
console.log(uniquesObj);
You can use Object.keys() and map() to create key for each object and filter to remove duplicates.
var array = [{
id: 1,
label: 'one'
}, {
id: 1,
label: 'one'
}, {
id: 2,
label: 'two'
}];
var result = array.filter(function(e) {
var key = Object.keys(e).map(k => e[k]).join('|');
if (!this[key]) {
this[key] = true;
return true;
}
}, {});
console.log(result)
You could use a hash table and store the found id.
var array = [{ id: 1, label: 'one' }, { id: 1, label: 'one' }, { id: 2, label: 'two' }],
uniqueProducts = array.filter(function(elem) {
return !this[elem.id] && (this[elem.id] = true);
}, Object.create(null));
console.log('uniqueProducts', uniqueProducts);
Check with all properties
var array = [{ id: 1, label: 'one' }, { id: 1, label: 'one' }, { id: 2, label: 'two' }],
keys = Object.keys(array[0]), // get the keys first in a fixed order
uniqueProducts = array.filter(function(a) {
var key = keys.map(function (k) { return a[k]; }).join('|');
return !this[key] && (this[key] = true);
}, Object.create(null));
console.log('uniqueProducts', uniqueProducts);
You can use reduce to extract out the unique array and the unique ids like this:
var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];
var result = array.reduce(function(prev, curr) {
if(prev.ids.indexOf(curr.id) === -1) {
prev.array.push(curr);
prev.ids.push(curr.id);
}
return prev;
}, {array: [], ids: []});
console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}
If you don't know the keys, you can do this - create a unique key that would help you identify duplicates - so I did this:
concat the list of keys and values of the objects
Now sort them for the unique key like 1|id|label|one
This handles situations when the object properties are not in order:
var array=[{id:1,label:"one"},{id:1,label:"one"},{id:2,label:"two"}];
var result = array.reduce(function(prev, curr) {
var tracker = Object.keys(curr).concat(Object.keys(curr).map(key => curr[key])).sort().join('|');
if(!prev.tracker[tracker]) {
prev.array.push(curr);
prev.tracker[tracker] = true;
}
return prev;
}, {array: [], tracker: {}});
console.log(result);
.as-console-wrapper{top:0;max-height:100%!important;}

How to make Javascript map function not to return specific value?

I have this array and variable:
var freqId = 45;
$scope.frequencies = [{Id:124,name:'qqq'},
{Id:589,name:'www'},
{Id:45,name:'eee'},
{Id:567,name:'rrr'}]
I use this row to get all id's from array above:
var inspectionsId = $scope.frequencies.map(function (obj) { return obj.Id; })
The result I get is:
var Id's = [124,589,45,567];
I need to change this row:
$scope.frequencies.map(function (obj) { return obj.Id; })
to retrive all id from frequencies array except where Id equal to freqId variable.
For example desired result is:
var inspectionsId = [124,589,567];
Any idea how can I implemet it?
You can also use Array.prototype.reduce to do both filtering and mapping in a single loop:
var freqId = 45;
$scope = {}; // Dummy scope
$scope.frequencies = [{
Id: 124,
name: 'qqq'
}, {
Id: 589,
name: 'www'
}, {
Id: 45,
name: 'eee'
}, {
Id: 567,
name: 'rrr'
}]
var result = $scope.frequencies.reduce(function(result, current) {
if (current.Id != freqId) {
result.push(current.Id);
}
return result;
}, []);
console.log(JSON.stringify(result));
map is designed to transform data, not filter it. Chain it with filter for the latter.
var freqId = 45;
var input = [{
Id: 124,
name: 'qqq'
}, {
Id: 589,
name: 'www'
}, {
Id: 45,
name: 'eee'
}, {
Id: 567,
name: 'rrr'
}];
var output = input.map(function(obj) {
return obj.Id;
}).filter(function(element) {
return element != freqId
});
console.log(output);
You can use Array.prototype.filter:
var inspectionsId = $scope.frequencies
.map(function(obj) { return obj.Id; })
.filter(function(id) { return id !== 45 })
You'll have seen the filter answers. 99.999% of the time, that's the way to go.
If you have a truly massive array and you think it's important to make just a single pass through it, you could give yourself a function combining map and filter:
// A value to use to mean "leave entry out"
Object.defineProperty(Array.prototype, "OMIT", {
value: {}
});
// The utility function
Object.defineProperty(Array.prototype, "mapFilter", {
value: function(f, thisArg, omissionFlag) {
var result = [];
if (arguments.length < 3) {
omissionFlag = Array.OMIT;
}
Object.keys(this).forEach(function(index) {
var value = f.call(thisArg, this[index], index, this);
if (value !== omissionFlag) {
result.push(value);
}
}, this);
return result;
}
});
// Using it
var freqId = 45;
var input = [{Id: 124, name: 'qqq'}, {Id: 589, name: 'www'}, {Id: 45, name: 'eee'}, {Id: 567, name: 'rrr'}];
var output = input.mapFilter(function(obj) {
return obj.Id == freqId ? Array.OMIT : obj.Id;
});
console.log(output);
This version accepts up to three arguments:
The map/filter function
The value to use as this during callbacks
The value to use to mean "omit this entry," which defaults to Array.OMIT
It calls its callback with the value, index, and array just like forEach and map and such do.
Again, though, I'll emphasize that in the vast, vast majority of cases, filter and then map (or map and then filter if the map makes filtering easier) is the way to go.
That said, a generic "loop with memo" function has broader applicability:
// The utility function
Object.defineProperty(Array.prototype, "memoLoop", {
value: function(memo, f, thisArg) {
Object.keys(this).forEach(function(index) {
f.call(thisArg, memo, this[index], index, this);
}, this);
return memo;
}
});
// Using it
var freqId = 45;
var input = [{Id: 124, name: 'qqq'}, {Id: 589, name: 'www'}, {Id: 45, name: 'eee'}, {Id: 567, name: 'rrr'}];
var output = input.memoLoop([], function(result, obj) {
var id = obj.Id;
if (id != freqId) {
result.push(id);
}
});
console.log(output);
It's a bit like Array#reduce but assumes an unchanging memo value (in our case, the new array), which simplifies the callback somewhat.

Convert array of objects and their properties to array

I tried several of the map functions but could not find a proper way to get what I want. Here is the case:
Object {Results:Array[3]}
Results:Array[3]
[0-2]
0:Object
id=null
name: "Rick"
upper:"0.67"
1:Object
id="00379321"
name:null
upper:"0.46"
2:Object
id="00323113"
name:null
upper:null
I want my final result to look like this. I wanted all null values to be removed and all the entries tied up like this in an object.
var finalResult = ["Rick","0.67","00379321","0.46","00323113"];
How can I achieve this result?
_.chain(a)
.map(function(x) {return _.values(x)})
.flatten()
.filter(function(x) {return x != null;})
.value()
Small modification for #andrey's code (requires lodash.js)
var a = [{id:null, name: "Rick", upper:"0.67"}, {id:"00379321", name:null, upper:"0.46"}, {id: "00323113",name:null, upper:null}]
_(a)
.map(function(x) {return _.values(x)})
.flatten()
.without(null)
.value()
I suggest to use a fixed array for the keys, because the properties of an object have no order and the order is relevant.
var data = [{ id: null, name: "Rick", upper: "0.67" }, { id: "00379321", name: null, upper: "0.46" }, { id: "00323113", name: null, upper: null }],
result = [];
data.forEach(function (a) {
['id', 'name', 'upper'].forEach(function (k) {
if (a[k] !== null) {
result.push(a[k]);
}
});
});
console.log(result);
Another underscore solution, similar to the other underscore solutions, but uses reject and the isNull predicate:
var result = _.chain(data)
.map(_.values)
.flatten()
.reject(_.isNull)
.value();

Underscore.js nested groupings

I'm having trouble getting the output I need from the following json
[
{"Type":"A","Location":"1"},
{"Type":"A","Location":"2"},
{"Type":"A","Location":"3"},
{"Type":"B","Location":"2"},
{"Type":"B","Location":"3"},
{"Type":"C","Location":"1"},
{"Type":"A","Location":"1"},
{"Type":"A","Location":"1"},
{"Type":"A","Location":"3"},
{"Type":"C","Location":"1"},
{"Type":"C","Location":"1"},
{"Type":"C","Location":"1"}
]
my expected output is as follows:
[
{"Type":"A","Count":"6","Locations":
[
{"Location":"1","Count":"3"},
{"Location":"2","Count":"1"},
{"Location":"3","Count":"2"}
]
},
{"Type":"B","Count":"2","Locations":
[
{"Location":"2","Count":"1"},
{"Location":"3","Count":"1"}
]
},
{"Type":"C","Count":"4","Locations":
[
{"Location":"1","Count":"4"}
]
}
]
The code I have so far will group the locations and give me the counts, but I'm stuck with the inner group
var result = _.chain($scope.incidents)
.groupBy("Type")
.map(function(value,key){
return{
Type:key,
Count:value.length
}
}).value();
Try this:
var result = _.chain($scope.incidents).groupBy('Type').map(function(value, key) {
return {
Count: value.length,
Type: key,
Locations: _.chain(value).groupBy('Location').map(function(value, key) {
return {
Location: key,
Count: value.length
};
}).value()
};
}).value();
I'm assuming you're using Lo-Dash, as underscore didn't seem to have the groupBy(<string>) feature.
In any case, here's a solution:
var result = _(list)
.groupBy('Type')
.map(function (locations, type) {
return {
Type: type,
Count: locations.length,
Locations: _(locations)
.groupBy('Location')
.map(function (arr, location) {
return {
Count: arr.length,
Location: location
};
}).value()
};
}).value();

Categories

Resources