How would you unify two similar array declarations - javascript

I have two similar array declarations:
allFalseOrTrue: any[] = [{'id': -1, 'name': 'All'}, {'id': 0, 'name': 'No'}, {'id': 1, 'name': 'Yes'}];
bothFalseOrTrue: any[] = [{'id': -1, 'name': 'Both'}, {'id': 0, 'name': 'No'}, {'id': 1, 'name': 'Yes'}];
Would you recommend to unify the arrays?
I mean I want to have some sort of base thing that I can use to construct my two other and similar arrays to avoid copypaste.
Say if I have something like a source array or enum and just based on that able to construct my other arrays.

How about use a function to create the array:
type Name = "All" | "Both" | "No" | "Yes";
function createOptions(...names: Name[]) {
return names.map((name, i) => ({ id: i - 1, name }));
}
const all_no_yes = createOptions("All", "No", "Yes");
const both_no_yes = createOptions("Both", "No", "Yes");
Or you could create a single array and filter down to the ones you want:
const all = [{ id: -1, name: "All" }, { id: -1, name: "Both" }, { id: 0, name: "No" }, { id: 1, name: "Yes" }];
const all_no_yes = all.filter(item => item.name != "Both");
const both_no_yes = all.filter(item => item.name != "All");
Also note that using any[] is blurring the type, if you allow the type to be inferred (as above with no type annotation) you'll get arrays with items of shape { id, name }, which is better.

Related

How to add property value from one array of objects into another (for the matching objects) in JS

I am trying to filter array of objects based on another array of objects and after finding all matching items I want to set property and value from the first array object into corresponding object in the second array:
const searchedProducts = products.filter(product =>
uniqueProducts.some(
uniqueProduct =>
product.productId === uniqueProduct.productId,
),
)
After here I need to set product.productName for each unique product object under productName property.
Ho such a thing can be achieved in a better way?
This is probably most straightforward using reduce() combined with find() to both retrieve and verify that the second array contains each object.
const uniqueProducts = [
{id: 3, from: 'uniqueProducts', name: 'Unique 1'},
{id: 12, from: 'uniqueProducts', name: 'Unique 12'}
];
const products = [
{id: 1, from: 'products', name: 'Product 1'},
{id: 2, from: 'products', name: 'Product 2'},
{id: 9, from: 'products', name: 'Product 9'},
{id: 12, from: 'products', name: 'Product 12'},
];
const output = products.reduce((a, p) => {
const uP = uniqueProducts.find(u => u.id === p.id);
if (uP) a.push({...p, name: uP.name});
return a;
}, []);
console.log(output);
I have inventory where I have to add a price property and take its value from products array so I did this,
inventory = [
{
"productId": 1,
"quantity": 100,
"name": "2 Yolks Noodles",
"image": "twoeggnoodles.jpg",
}
]
Products = [
{
"id": 1,
"quantity": 100,
"name": "2 Yolks Noodles",
"image": "twoeggnoodles.jpg",
"price": 34.95
}
]
let product:any = [];
products.map((prod:any)=>{
const index:any = inventory.find((u:any) => u.productId === prod.id);
// console.log("item", index, '-', prod)
if(index){
product.push({...index, price: prod.price});
}
return prod
})
});

Delete multiple objects in an array by id

I have a main array of objects with each object having some key/values as well as a "id" key with 1,2,3,4,5, etc
Now I have another array representing just id's (like [2,3])
I want to use this array to delete objects from the main array...so in this case, objects from the main array having id's 2 & 3 should be deleted
While I am aware of findBy(id), I am not sure if that can be used to delete multiple objects at once.
You can use filter. In the filter callback function check if the id is also there in id array by using includes
let idArr = [1, 2]
let obj = [{
id: 1,
name: 'abc'
},
{
id: 2,
name: 'abc'
},
{
id: 3,
name: 'abc'
},
{
id: 4,
name: 'abc'
}
];
let data = obj.filter(item => !idArr.includes(item.id));
console.log(data);
console.log(obj)
using filter might work well here. you could write something like:
var newArray = oldArray.filter(object => !ids.includes(object.id))
You can do it, like this:
[2,3].forEach(key => {
delete object[key];
})
You can use filter method for this.
Ex:
let id = 2;
let list = [{
Id: 1,
Name: 'a'
}, {
Id: 2,
Name: 'b'
}, {
Id: 3,
Name: 'c'
}];
let lists = list.filter(x => {
return x.Id != id;
})
console.log(lists);
Assuming you want to delete items from the original array by entirely removing the element from the array (and you don't want to get a new array), you can take advantage of
Array.splice
let idArr = [1, 2];
let obj = [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
for (let id of idArr) {
// look for the element by its id.
const objIdRef = obj.find(i => i.id === id);
// if it actually exists, splice it.
objIdRef && obj.splice(obj.indexOf(objIdRef), 1);
}
console.log(obj);
If the obj array is big, you might want to make a map from it before processing the id array, so that the complexing is reduced to O(1) when the delete process begins.
Perhaps This is what you want:
var arr= [{id:1, name: "foo"}, {id:2, name: "bar"}, {id:3, name:"not to be deleted"}];
var idsToDelete = [1, 2];
var res = arr.map((i, idx)=>{
return arr[idx] = idsToDelete.includes(i.id)? undefined : arr[idx]
}).filter(i=>i)
console.log(res)
You can try Lodash.js functions _.forEach() and _.remove()
let valuesArr = [
{id: 1, name: "dog"},
{id: 2, name: "cat"},
{id: 3, name: "rat"},
{id: 4, name: "bat"},
{id: 5, name: "pig"},
];
let removeValFromIndex = [
{id: 2, name: "cat"},
{id: 5, name: "pig"},
];
_.forEach(removeValFromIndex, (indi) => {
_.remove(valuesArr, (item) => {
return item.id === indi.id;
});
})
console.log(valuesArr)
/*[
{id: 1, name: "dog"},
{id: 3, name: "rat"},
{id: 4, name: "bat"},
]; */
Don't forget to clone (_.clone(valuesArr) or [...valuesArr]) before mutate your array

How to display one item per `type` attribute in a list?

I am writing an Angular 8 application. In one of the views there is the option to display a list of items of class Product and this list may be filtered in several ways.
export class Product {
constructor(
public id: number,
public type: number
) {
}
}
What I want to do:
Among the attributes of Product there is type. How can I filter them in order to obtain exactly one item per type? What I would do is use this function, but I don't know how to write the logical statement in parentheses.
filterItemsOnePerType() {
this.filteredProducts = Object.assign([], this.products).filter(
item => (... item.type ...)
);
}
Notice that it's not really important the item that is going to be selected. What is important is that in the final view I won't see any duplicate among types.
EXAMPLE
I have a list of products:
[{id: 1, type:1},
{id: 2, type:1},
{id: 3, type:1},
{id: 4, type:2},
{id: 5, type:2},
{id: 6, type:3},
{id: 7, type:2}]
What I want to obtain is therefore the following list:
[{id: 1, type:1},
{id: 4, type:2},
{id: 6, type:3}]
this.filteredProducts = Object.assign([], this.products).filter(
(types => item => !types.has(item.type) && types.add(item.type))(new Set)
);
You might want to use a Set to exclude duplicates.
You could use the Array.reduce method to filter it out.
const array = [
{ id: 1, type: 1 },
{ id: 2, type: 1 },
{ id: 3, type: 1 },
{ id: 4, type: 2 },
{ id: 5, type: 2 },
{ id: 6, type: 3 },
{ id: 7, type: 2 }
];
const result = array.reduce((result, item) => {
const isFound = result.find(({ type }) => item.type === type);
if (isFound) {
return result;
}
return [...result, item];
}, []);
console.log(result);
Going back to your original code, you'd do something like the following:
filterItemsOnePerType() {
this.filteredProducs = Object.assign([], this.producs).reduce(
(result, item) => {
const isFound = result.find(
({ type }) => item.type === type
)
if (isFound) return result
return [...result, item]
}, []
)
}
Hope this helps.

Typescript difference of two object arrays

I have two object arrays and want to find the items that are missing in the second array but are part of the first array,basically array1-array2.I tried to use filter but I'm unable to get the desired result.Please help.Thanks in advance.
Here is the code:
testData=[
{id: 0, name: "policy001"},
{id: 2, name: "policy002"}];
sourceData= [
{id: 0, name: "policy001"},
{id: 2, name: "policy002"},
{id: 3, name: "policy003"},
{id: 4, name: "policy004"},
{id: 5, name: "policy005"},
];
let missing = sourceData.filter(item => testData.indexOf(item) < 0);
console.log("Miss")
console.log(missing )//Returns the sourceData instead of diff.
Try findIndex():
The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise, it returns -1, indicating that no element passed the test.
testData = [{
id: 0,
name: "policy001"
},
{
id: 2,
name: "policy002"
}
];
sourceData = [{
id: 0,
name: "policy001"
},
{
id: 2,
name: "policy002"
},
{
id: 3,
name: "policy003"
},
{
id: 4,
name: "policy004"
},
{
id: 5,
name: "policy005"
},
];
console.log(sourceData.filter(item => testData.findIndex(x => x.id == item.id) < 0))
The reason your code did not work is that object inside array are "addresses" to the objects. So of course the indexOf did not work
try below:
let missing = sourceData.filter(a => !testData.find(b => a.id === b.id));
You're getting this undesired behavior because what you're doing in your filter is comparing the items' references rather than their values. if you want to compare that those objects are actually identical in values (because they have different references), you need to do the following:
let missing = sourceData.filter(sourceItem =>
testData.every(testItem =>
testItem.id !== sourceItem.id && testItem.name !== sourceItem.name
)
)
this means - filter out those element of sourceData, for which none of the elements in testData has the same id or name. They are "missing".

Javascript how to filter an array using forEach() inside filter()

I have an array of objects and I'd like to filter it based on the objects property values. I'd like to filter it by different properties, so it needed to be dynamic. For this I have an input field where I type and then filter the array. So, let's say I have these 2 different arrays:
const array_one = [
{id: 1, code: 'ABC123', name: 'John'},
{id: 2, code: 'DEF456', name: 'Stew'},
// ...
];
const array_two = [
{id: 1, value: '012345', company: 'Company 01' },
{id: 2, value: '678910', company: 'Company 02' },
// ...
];
I want a function where I can filter the first array based on the name, also If I want to filter the second array, I want to filter it by the value.
For this, I built this function:
filterArray(array: Array<any>, fields: Array<any>, value: string) {
value = this.convertString(value);
array = array.filter((item) => {
fields.forEach(obj => {
if ( item[obj] ) {
const _newObj = this.convertString(item[obj]);
if ( _newObj.indexOf(value) !== -1 ) {
console.log(item);
return item;
}
}
});
});
return array;
}
// convertString() is just another function to replace accents, spaces, etc...
Then I call it like this:
filterArray(originalArray, ['name'], valueFromInput);
// or...
filterArray(originalArray, ['value'], valueFromInput);
// or even...
filterArray(originalArray, ['value', 'company'], valueFromInput);
But the array filtered is always returnin empty, even if the console inside the indexOf verification prints the correct object on the console.
What am I doing wrong here? Because it's filtering properly, I have manually checked it, but it doesn't add to the new filtered array.
You can iterate the fields using Array#some, and if one of them is equal to value return the item:
const array_one = [
{id: 1, code: 'ABC123', name: 'John'},
{id: 2, code: 'DEF456', name: 'Stew'}
];
const array_two = [
{id: 1, value: '012345', company: 'Company 01' },
{id: 2, value: '678910', company: 'Company 02' }
];
const filterArray = (array, fields, value) => {
fields = Array.isArray(fields) ? fields : [fields];
return array.filter((item) => fields.some((field) => item[field] === value));
};
console.log(filterArray(array_one, 'name', 'Stew'));
console.log(filterArray(array_two, ['id', 'company'], 2));
console.log(filterArray(array_two, ['id', 'company'], 'Company 02'));
If you want to make the filter about more than one filed then the value that you send it to the function, should be also array.
In my code below I assume that you want to return the object that Achieves all conditions (contains all properties that you send to the function with the same value)
const array_one = [
{id: 1, code: 'ABC123', name: 'John'},
{id: 2, code: 'DEF456', name: 'Stew'},
];
const array_two = [
{id: 1, value: '012345', company: 'Company 01' },
{id: 2, value: '678910', company: 'Company 02' },
];
function filterArray(array, fields, value) {
array = array.filter((item) => {
const found = fields.every((field, index) => {
return item[field] && item[field] === value[index]
})
return found
});
return array;
}
console.log(filterArray(array_one, ['name'], ['Stew']));
console.log(filterArray(array_two, ['id', 'company'], [1,'Company 01']));

Categories

Resources