Angular remove object from array search for key and value - javascript

I need to remove an entry from an array by searching for the id value.
The data looks like this:
data = [ { "id": "02" }, { "id": "03" } ];
And I need a method like:
remove(keyValue) {
// do something here
}
Usage example:
remove('02');
Then it would search the id key with value "02" and remove the data so it would remove like this:
data = [ { "id": "03" } ];
How can I do this?

Works if key is "id", and if you are sure there won't be repeated values:
var data = [ { "id": "02" }, { "id": "03" } ];
function removeVal(value) {
var removeIndex = -1;
data.forEach((obj, index) => {
if (obj.id === value) {
removeIndex = index;
}
});
data.splice(removeIndex, 1);
console.log(data);
}
removeVal("02");

You could implement something like this https://stackblitz.com/edit/typescript-g3gty2
where the method remove accepts the initial array, the key and the value to remove.
function remove(data: any[], key: string, value: any) {
return data.filter(d => d[key] !== value);
}

If you use Typescript remove quotes from property names.
data = [ { id: "02" }, { id: "03" } ];
You can use findIndex function to get the index of specific element. After you got the index you can delete the element with splice function.
remove(keyValue: String) {
let objectIndex = this.data.findIndex(e => e.id == keyValue);
if(objectIndex != -1) {
this.data.splice(objectIndex, 1); // Remove one element from array
}
}

Related

Comparing two array of objects and replacing an object with another

I have a working function that appends an array of objects customData to the end of another array of objects testData. If an object with the same property name value appears in both arrays, then the testData object is removed and replaced with the customData object in the resulting array. The customData object takes on the order of the previous testData object.
This is my attempt however, I'm wondering if there is a better way of doing this which is also easy to read (es6)?
Thanks
https://codesandbox.io/s/recursing-river-bdp5k?file=/src/App.js
export default function App() {
const testData = [
{ display: "1", name: "TEST1" },
{ display: "2", name: "TEST2" }
];
const customData = [
{ display: "CUSTOM_1", name: "TEST1", custom: "YES" },
{ display: "CUSTOM_3", name: "TEST3", custom: "YES" }
];
let i = 0;
const newTestData = testData;
let newCustomData = customData;
while (i < customData.length) {
const view = customData[i];
const index = testData.findIndex(x => x.name === view.name);
if (index >= 0) {
newTestData[index] = customData[i];
newCustomData.splice(i, 1);
}
i += 1;
}
const concatData = newTestData.concat(newCustomData);
console.log(concatData)
return null;
}
Array#concat does not mutate the arrays, there's no need to assign them to new variables (which doesn't copy the arrays anyway). If you're seeking to use concise ES6 code, skip the while loop - there are numerous equivalents. Here's one example:
You don't define "better way" but I'll interpret it to mean "most optimized for performance and readability". In the below approach I use one pass to populate a map, and another pass to overwrite the map entries with customData where needed, and finally a Object.values() (technically a third pass) to produce the results. This is O(n) (no nested loops) versus your O(n^2) implementation.
const testData = [
{ display: "1", name: "TEST1" },
{ display: "2", name: "TEST2" }
];
const customData = [
{ display: "CUSTOM_1", name: "TEST1", custom: "YES" },
{ display: "CUSTOM_3", name: "TEST3", custom: "YES" }
];
let map = {};
testData.forEach(item => map[item.name] = item);
customData.forEach(item => map[item.name] = item);
const result = Object.values(map);
console.log(result);
For many cases including this one, where you have a bunch of data identified by a unique key (such as name), you really ought to be using objects to begin with. Any time you need an array, there's Object.values() and Object.keys().
Logic behind your code is correct.
This is almost the same, but without explicit loops:
const testData = [
{ display: "1", name: "TEST1" },
{ display: "2", name: "TEST2" }
];
const customData = [
{ display: "CUSTOM_1", name: "TEST1", custom: "YES" },
{ display: "CUSTOM_3", name: "TEST3", custom: "YES" }
];
Array.prototype.uniqueWith = function(comparator) {
return this.reduce((a, c, i) => {
const j = a.slice(i+1).findIndex(e => comparator(e, c));
if(j !== -1) {
a[i] = a[i+j+1];
a.splice(i+j+1, 1);
}
return a;
}, this);
}
const eqByName = (a, b) => a.name === b.name;
const result = [...testData, ...customData].uniqueWith(eqByName);
console.log(result);
Take a note that extending Array prototype may not be the best idea, so you may create separate function, which will take concatenated array as an argument.
Is this the kind of function you're looking for?
const result = App(myTestData(), myCustData());
console.log(result);
function App(testData, custData) {
// `indByName` returns index (in arr) of obj w/ matching name (or -1 if no match)
const indByName = (arr, name) =>
ind = arr.findIndex(o => o.name === name);
let custInd; // Identifier for output of `indByName`
const custDataClone = custData.slice(); // Prevents mutating `custData`
return testData.map(item => (
// Uses indByName to get index of corresponding custom item
custInd = indByName(custDataClone, item.name),
// Moves corresponding custom item into testData if appropriate
custInd > -1 ? custDataClone.splice(custInd, 1)[0] : item
// Appends remaining items from custDataClone to the new array
)).concat(custDataClone)
}
function myTestData(){
return [
{ display: "1", name: "TEST1" },
{ display: "2", name: "TEST2" }
];
}
function myCustData(){
return [
{ display: "CUSTOM_1", name: "TEST1", custom: "YES" },
{ display: "CUSTOM_3", name: "TEST3", custom: "YES" }
];
}

How to flatten objects in JavaScript (with or without lodash)?

I have an object like
farmer:{
name: "First Name",
bank: {
id: 7
}
certifications: [
{
certificateNumber: {
id : 7
},
certificateNumber: {
id : 8
}
}
]
}
I have tried using lodash's set and unset method but that results in undefined values a lot often.I want to remove the id key from the above object completely
This is the result i want
farmer:{
name: "First Name",
bank: 7
certifications: [
{
certificateNumber: 7,
certificateNumber: 8
}
]
}
You can use lodash's _.transform() to iterate the structure recursively, and if an object has an id property, and its size (number of properties) is 1, replace the object with the id value.
Note: the certifications array is malformed and was changed to the following form [{certificateNumber:{id:7}},{certificateNumber:{id:8}}].
const fn = obj => _.transform(obj, (accumulator, value, key) => {
let val = value
if(_.has(value, 'id') && _.size(value) === 1) val = _.get(value, 'id')
else if(_.isObject(value)) val = fn(value)
accumulator[key] = val
})
const farmer = {"name":"First Name","bank":{"id":7},"certifications":[{"certificateNumber":{"id":7}},{"certificateNumber":{"id":8}}]}
const result = fn(farmer)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.14/lodash.js"></script>

how to get unique values from array of objects with addition of numbers

I'm working in wso2 carbon dashboard. My table is containing 2 fields (Name and Number). I Have duplicate name in the objects but with different number. I want unique name with addition of numbers.
[
{
"Name":"Abc",
"number":2
},
{
"Name":"bcd",
"number":3
},
{
"Name":"Abc",
"number":5
}
]
expected output
[
{
"name":"Abc",
"Number":7
},
{
"name":"bcd",
"Number":3
}
]
I'm using java script to achieve such task. please help me
Use Array#reduce method with a reference object.
var data = [{
"Name": "Abc",
"number": 2
}, {
"Name": "bcd",
"number": 3
}, {
"Name": "Abc",
"number": 5
}];
// object for index reference
var ref = {};
// iterate and generate the array
var res = data.reduce(function(arr, o) {
// check index already defined
if (!(o.Name in ref)) {
// if not defined then define index
ref[o.Name] = arr.length;
// and push the element
// you can also use
// arr.push({Name:o.Name, number:o.number});
arr.push(Object.assign({}, o));
} else {
// if index already defined update the number
arr[ref[o.Name]].number += o.number;
}
// return the array reference
return arr;
// set initial value as empty array
}, []);
console.log(res);

Filtering array of Objects Using Lodash or Javascript based on property name

I am Having the Array of objects. Like this
var result=[{"batchId":123, "licenseId":2345ef34, "name":"xxx"},
{"batchId":345, "licenseId":2345sdf334, "name":"www"},
{"batchId":145, "licenseId":234sdf5666, "name":"eee"},
{"batchId":455, "licenseId":asfd236645 },
{"batchId":678, "name":"aaa"}]
i want to have the array which is contains all the three properties. the Output should be like this.
[{"batchId":123, "licenseId":2345ef34, "name":"xxx"},
{"batchId":345, "licenseId":2345sdf334, "name":"www"},
{"batchId":145, "licenseId":234sdf5666, "name":"eee"}]
can anybody Help me on this
This is simple with the array .filter() method:
var result=[
{"batchId":123, "licenseId":"2345ef34", "name":"xxx"},
{"batchId":345, "licenseId":"2345sdf334", "name":"www"},
{"batchId":145, "licenseId":"234sdf5666", "name":"eee"},
{"batchId":455, "licenseId":"asfd236645" },
{"batchId":678, "name":"aaa"}
];
var filtered = result.filter(function(v) {
return "batchId" in v && "licenseId" in v && "name" in v;
});
console.log(filtered);
The function you pass to .filter() is called for each element in the array. Each element for which you return a truthy value will be included in the resulting array.
In the code above I simply test if all three of those specific properties are present, although there are other tests you could use that would get the same result for that data:
var result=[ {"batchId":123, "licenseId":"2345ef34", "name":"xxx"}, {"batchId":345, "licenseId":"2345sdf334", "name":"www"}, {"batchId":145, "licenseId":"234sdf5666", "name":"eee"}, {"batchId":455, "licenseId":"asfd236645" }, {"batchId":678, "name":"aaa"} ];
var filtered = result.filter(function(v) {
return Object.keys(v).length === 3;
});
console.log(filtered);
Note that you need to put your licenseId values in quotes, because they seem to be string values.
var result = [{
"batchId": 123,
"licenseId": '2345ef34',
"name": "xxx"
}, {
"batchId": 345,
"licenseId": '2345sdf334',
"name": "www"
}, {
"batchId": 145,
"licenseId": '234sdf5666',
"name": "eee"
}, {
"batchId": 455,
"licenseId": 'asfd236645'
}, {
"batchId": 678,
"name": "aaa"
}];
function hasProperties(object) {
return object.hasOwnProperty('batchId') && object.hasOwnProperty('licenseId') && object.hasOwnProperty('name')
}
result.filter(e => hasProperties(e));

Array of objects

I have an array of objects, an example of a few of them being
[
{
"lang_code": "eng",
"site_language": "1",
"name": "English"
},
{
"lang_code": "afr",
"site_language": "1",
"name": "Afrikaans"
},
{
"lang_code": "ale",
"site_language": "0",
"name": "Aleut"
},
]
I want to be able to search the whole array for a specific lang_code, let's say I use eng. I want to search the whole array for eng. If it's there, I want it to return English, if not, I want it to return invalid. Any ideas on this?
A generic and more flexible version of the findById function above:
// array = [{key:value},{key:value}]
function objectFindByKey(array, key, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
return null;
}
var array = your array;
var result_obj = objectFindByKey(array, 'lang_code', 'eng');
Click here for demo
You could use filter:
function findLang(arr, code) {
var filtered = arr.filter(function (el) {
return el.lang_code === code;
});
// filter returns an array of objects that match the criteria
// if the array is not empty return the language,
// otherwise return 'invalid'
return filtered.length > 0 ? filtered[0].name : 'invalid';
}
findLang(arr, 'eng'); // English
DEMO
If you wanted to add map into the mix instead of using that ternary operation (but which would most likely be slower and doesn't really provide any additional benefit):
function findLang(arr, code) {
return arr.filter(function (el) {
return el.lang_code === code;
}).map(function (el) {
return el.name;
})[0] || 'invalid';
}
DEMO
How about a for loop. Something like:
function find_lang(input_arr, lang_code) {
for(var i = 0; i < input_arr.length; i++) {
var o = input_arr[i];
if( o.lang_code === lang_code ) {
return o.name;
}
}
return "invalid";
}
Underscore.js has some useful helpers for this kind of thing: http://underscorejs.org/
E.g Find:
Looks through each value in the list, returning the first one that
passes a truth test (predicate), or undefined if no value passes the
test. The function returns as soon as it finds an acceptable element,
and doesn't traverse the entire list.
var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> 2
Where:
Looks through each value in the list, returning an array of all the
values that contain all of the key-value pairs listed in properties.
_.where(listOfPlays, {author: "Shakespeare", year: 1611});
=> [{title: "Cymbeline", author: "Shakespeare", year: 1611},
{title: "The Tempest", author: "Shakespeare", year: 1611}]
You could do it this way:
// configure your parameters
function checkArr(){
for (var i = 0; i < x.length; i++){
if (x[i].lang_code == "eng")
return "English";
}
return "invalid";
}
var x = [
{
"lang_code": "eng",
"site_language": "1",
"name": "English"
},
{
"lang_code": "afr",
"site_language": "1",
"name": "Afrikaans"
},
{
"lang_code": "ale",
"site_language": "0",
"name": "Aleut"
}
];

Categories

Resources