Related
I'm working on a checkbox ui react web app, where in, on check we dispatch items array with a object in it, and on uncheck also we dispatch items array with object in it. So I need to add this logic - Check if object of any array exist in an another array, if not exists then push onto another array , or else remove it from another array
let items1 = [{ name: "a" }, { name: "b" }, { name: "c" }];
let items2 = [{ name: "a" }, { name: "d" }, { name: "e" }];
const commonItems = items1.filter((x) => items2.some((y) => y.name === x.name));
if (!commonItems) {
items1.push(...items2);
} else {
items1 = items1.filter((x) => items2.some((y) => y.name !== x.name));
}
console.log(items1);
console.log(items2);
Check if object of any array exist in an another array, if not exists then push onto another array , or else remove it from another array,
Is this code corect for above logic?
Couple of issues. 1) commonItems is always a truth value because filter returns empty array when no results, so always going to else block 2) Else block filter is not correct. (updated here to use !some)
let items1 = [{ name: "a" }, { name: "b" }, { name: "c" }];
let items2 = [{ name: "a" }, { name: "d" }, { name: "e" }];
const commonItems = items1.filter((x) => items2.some((y) => y.name === x.name));
console.log(commonItems)
if (commonItems.length < 1) {
items1.push(...items2);
} else {
items1 = items1.filter((x) => !items2.some((y) => y.name === x.name));
}
console.log(items1);
console.log(items2);
I have a delete function that looks like this:
this.deleteItem = item => event => {
const { res, selectedItems } = this.state;
res.splice(res.indexOf(item), 1);
selectedItems.splice(res.indexOf(item), 1);
this.setState({
res
});
};
Here, the res is the list of items displayed on the page, and selectedItems is a list of which of those items are selected. When an item from res is deleted, selectedItems should be updated to remove the index of that item from the list.
Whenever I try to delete a specific item however, it just deletes the last item added to the array, rather than the item that corresponds to the index of the target clicked. Something must be going on with the way it's being indexed, but I've been having trouble identifying the source.
I've also tried as referenced here, but this didn't work since I need to take in item as a parameter.
What would be a good way to go about this?
Thank you very much.
EDIT: Changed the function to look like #HMK's response. After an item is deleted, the output of console.log(res) in the render method is an array of objects which has the form:
res
(9) […]
0: Object { id: 0, name: "a", description: "description of a", … }
1: Object { id: 2, name: "b", description: "description of b", … }
2: Object { id: 3, name: "c", description: "description of c", … }
3: Object { id: 4, name: "d", description: "description of d", … }
4: Object { id: 5, name: "e", description: "description of e", … }
5: Object { id: 6, name: "f", description: "description of f", … }
6: Object { id: 7, name: "g", description: "description of g", … }
7: Object { id: 8, name: "h", description: "description of h", … }
8: Object { id: 9, name: "i", description: "description of i", … }
length: 9
<prototype>: Array []
The output of console.log(JSON.stringify(item,undefined,2)); in the deleteItem function is the object that is deleted from the array.
e.g.:
{
"id": 10,
"name": "j",
"description": "description of j",
"icon": "jIcon",
"selected": false
}
When all items on the page are selected, the output of console.log("selecteditems:", JSON.stringify(selectedItems)):
selecteditems: [0,1,2,3,4,5,6,7,8,9,10]
To take out an item from an array you can do the following:
array.filter(item=>item!==itemToRemove)
So in your example:
this.deleteItem = item => event => {
const filter = getter => val => getter(val) !== item.id
this.setState({
res: this.state.res.filter(filter(({id})=>id)),
selectedItems: this.state.selectedItems.filter(
filter(id=>id)
)
})
}
The problem you have is that res stores an array of objects that have an id (for example: [{id:1}], then selectedItems is an array that stores the id: (for example: [1]).
Array.prototype.filter works in the following way: newArray = array.filter(filterFunction). For each item in array filterFunction is called with that item. If filterFunction returns false then that item is not copied to newArray, it it returns true it is copied to newArray. The original array stays untouched (as it should be with state because you should not mutate it).
So the problem is that your filter function gets an item of the array, decides if it should return true or false (true to keep the item and false to not keep it). So if I filter res the filter function will receive {id:X} (object with an id) but when I filter selectedItems I will receive X (the id).
So the filter function needs to take out element(s) with a certain id, however; with res that id is a property of an object and with selectedItems it is an id. For res you can write a getter function to get the id out of the object: resItem=>resItem.id, give that function an item from res and it'll return an id. For selectedItems the getter function should just return the value it's given because items in selectedItems are ids, so that getter function looks like id=>id
Ok, lets' get back to filter, I have an array of id's called selectedItems [9] and want to remove id with value 9, let's call that idToRemove so I can do: selectedItems.filter(id=>id!==idToRemove). That same function won't work with res because {id:9} never equals 9.
But what if I pass a selector to the filter function, here it gets a bit complicated because functions can return a function:
const idToRemove = 9;
//filter function return true for array item to stay in the copied array
// and false to not include the array item in the copy
const filter = getter => arrayItem =>
getter(arrayItem) !== idToRemove;
//passing filter a getter function will return a function that takes
// an item and uses the getter function on that item to compare it
// to idToRemove
const compareId = filter(id => id);
console.log('keep 9?', compareId(9));
console.log('keep 8?', compareId(8));
//now create a filter function that takes an object and uses
// the getter to get object.id and compares that to idToRemove
const compareObjectWithId = filter(object => object.id);
console.log('keep {id:9}?', compareObjectWithId({ id: 9 }));
console.log('keep {id:8}?', compareObjectWithId({ id: 8 }));
So compareId is a function we can use to filter out an item from selectedItems and compareObjectWithId is a function we can use to filter out an item from res here is how the filter is used:
const idToRemove = 9;
const createFilterFunction = getter => arrayItem =>
getter(arrayItem) !== idToRemove;
console.log(
'[2,9] remove id 9',
[2, 9].filter(createFilterFunction(id => id))
);
console.log(
'[{id:2},{id:9}] remove id 9',
[{ id: 2 }, { id: 9 }].filter(
createFilterFunction(object => object.id)
)
);
For completion I will add modern code to remove a key from an object (don't try this on stack overflow code snippet because it's using an ancient babel version)
const org = {a:1,b:2};
const withoutA = Object.fromEntries(
Object.entries(org).filter(([key])=>key!=='a')//removed key 'a'
)
I have an array of objects . I need to convert the value of the 'key' by incrementing count .
lets say I have an array
const arr1=[{key:'a', val:1},{key:'b',val:2}]
I want to give an incrementing key value to each key
I have tried the below code but couldn't override the count value
let count = 0;
const arr1=[{key:'a', val:1},{key:'b',val:2}]
arr1.map(el => el.key=count+1);
console.log(arr1)
Expected Result :
[ { key: 1, val: 1 }, { key: 2, val: 2 } ]
You could use forEach to loop through the array and update the key based on the index
const array = [ { key: 1, val: 1 }, { key: 2, val: 2 } ]
array.forEach((o, i) => o.key = i+1)
console.log(array)
If you want a new array you could use map like this:
const array = [ { key: 1, val: 1 }, { key: 2, val: 2 } ],
newArray = array.map((o, i) => ({ ...o, key: i+1}));
console.log(newArray)
Because it looks like you want to perform side-effects rather than create a new array, use forEach instead of .map. You also need to actually increment the count variable on each iteration:
let count = 0;
const arr1=[{key:'a', val:1},{key:'b',val:2}]
arr1.forEach(el => {
count++;
el.key = count;
});
console.log(arr1)
Use ++ to update count while getting the new value. Also, you need to return the modified el from map, and make sure you assign the return value otherwise it'll be garbage-collected - map returns a new array.
let count = 0;
const arr1 = [{key:'a',val:1},{key:'b',val:2}];
const res = arr1.map(({ val }) => ({ key: ++count, val }));
console.log(res);
My array looks like this:
array = [object {id: 1, value: "itemname"}, object {id: 2, value: "itemname"}, ...]
all my objects have the same attibutes, but with different values.
Is there an easy way I can use a WHERE statement for that array?
Take the object where object.id = var
or do I just need to loop over the entire array and check every item? My array has over a 100 entries, so I wanted to know if there was a more efficient way
Use Array.find:
let array = [
{ id: 1, value: "itemname" },
{ id: 2, value: "itemname" }
];
let item1 = array.find(i => i.id === 1);
Array.find at MDN: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/find
I'd use filter or reduce:
let array = [
{ id: 1, value: "itemname" },
{ id: 2, value: "itemname" }
];
let item1 = array.filter(item => item.id === 1)[0];
let item2 = array.reduce((prev, current) => prev || current.id === 1 ? current : null);
console.log(item1); // Object {id: 1, value: "itemname"}
console.log(item2); // Object {id: 1, value: "itemname"}
(code in playground)
If you care about iterating over the entire array then use some:
let item;
array.some(i => {
if (i.id === 1) {
item = i;
return true;
}
return false;
});
(code in playground)
You can search a certain value in array of objects using TypeScript dynamically if you need to search the value from all fields of the object without specifying column
var searchText = 'first';
let items = [
{ id: 1, name: "first", grade: "A" },
{ id: 2, name: "second", grade: "B" }
];
This below code will search for the value
var result = items.filter(item =>
Object.keys(item).some(k => item[k] != null &&
item[k].toString().toLowerCase()
.includes(searchText.toLowerCase()))
);
Same approach can be used to make a Search Filter Pipe in angularjs 4 using TypeScript
I had to declare the type to get it to work in typescript:
let someId = 1
array.find((i: { id: string; }) => i.id === someId)
You'll have to loop over the array, but if you make a hashmap to link each id to an index and save that, you only have to do it once, so you can reference any objeft after that directly:
var idReference = myArray.reduce(function( map, record, index ) {
map[ record.id ] = index;
return map;
}, {});
var objectWithId5 = myArray[ idReference["5"] ];
This does assume all ids are unique though.
I'm trying to get some array data into a particular format so I can use google linechart. But I can't quite get it right.
Right now I have the format
//format [date, id, count
var data = [
["2014-04-01", "1", "100"],
["2014-04-02", "1", "200"],
["2014-04-03", "1", "150"],
["2014-04-04", "1", "5"],
["2014-04-01", "2", "200"],
["2014-04-02", "2", "600"],
["2014-04-03", "2", "15"],
["2014-04-04", "2", "25"],
["2014-04-01", "3", "99"],
["2014-04-02", "3", "85"],
["2014-04-03", "3", "555"],
["2014-04-04", "3", "0"]
];
I need to get it into the format:
var reformatted = [
['Date', '1', '2', '3'],
['2014-04-01', 100, 200, 99],
['2014-04-02', 200, 600, 85],
['2014-04-03', 150, 15, 555],
['2014-04-04', 5, 25, 0]
]);
var graph = [["date"]];
//first element of array to be populated with array of ID's
//always second element of inner arrays
//these will be the lines of the graph
for (var i = 0; i < data.length; i++){
if (graph[0].indexOf(data[i][1]) < 0){
graph[0].push(data[i][1]);
}
}
This puts me in a pretty good place. I get:
Array[1]]
0: Array[4]
0: "date"
1: "1"
2: "2"
3: "3"
But I'm stumped on how to get the rest of the data in the appropriate format. Any ideas?
Tried this. No good result.
for (i = 0; i < data.length; i++){
graph[i + 1] = graph[i + 1] || [];
graph[i + 1].push(data[i][2]);
}
Logic:
First generate this by iterating through the initial array finding unique dates.
[
['Date'],
['2014-04-01'],
['2014-04-02'],
['2014-04-03'],
['2014-04-04']
]
Then convert the generated array as follows again iterating through the initial array finding unique numbers. Also generate list of unique numbers.
[
['Date','1','2','3'],
['2014-04-01'],
['2014-04-02'],
['2014-04-03'],
['2014-04-04']
]
Now iterate through above array, and for each item iterate through the number list and find matches from the initial array where date and number matches. place the matches in the above array. Place a null if not found. You should get the following. I have done this in php but not in javascript.
[
['Date','1','2','3'],
['2014-04-01', null, 100, 200],
['2014-04-02', 100, 400, 500],
['2014-04-03', 200, null, 100],
['2014-04-04', 100, 300, 100]
]
Good Luck!
addition
In php:
$originalData = array(
array("2014-04-01", '1', '200'),
array("2014-04-02", '1', '300'),
array("2014-04-03", '1', '400'),
array("2014-04-04", '1', '200'),
array("2014-04-01", '2', '400'),
array("2014-04-02", '2', '100'),
array("2014-04-03", '2', '200'),
array("2014-04-04", '2', '100'),
array("2014-04-01", '3', '200'),
array("2014-04-02", '3', '600'),
array("2014-04-03", '3', '300'),
array("2014-04-04", '3', '900'),
);
result from second step would be:
$graphData = array(
array('Date','1','2','3'),
array('2014-04-01'),
array('2014-04-02'),
array('2014-04-03'),
array('2014-04-04'),
);
list of numbers would be:
$numbers = array('1','2','3');
I would then do the third step as follows:
$i = 0;
foreach($graphData as $graphDataItem) {
if ($graphDataItem[0]!='Date') { // ignore the first index
$j = 1; // 0 is date column
foreach($numbers as $number) {
foreach($originalData as $originalDataItem) {
// set the value to null until found
if (!isset($graphData[$i][$j]))
$graphData[$i][$j] = null;
if ($originalDataItem[0] == $graphDataItem[0] && // check date match
$originalDataItem[1] == $number) { // check number match
$graphData[$i][$j] = $originalDataItem[2];
break;
}
}
$j++;
}
}
$i++;
}
The resulting $graphData would be:
array
(
0 => array
(
0 => 'Date'
1 => '1'
2 => '2'
3 => '3'
)
1 => array
(
0 => '2014-04-01'
1 => '200'
2 => '400'
3 => '200'
)
2 => array
(
0 => '2014-04-02'
1 => '300'
2 => '100'
3 => '600'
)
3 => array
(
0 => '2014-04-03'
1 => '400'
2 => '200'
3 => '300'
)
4 => array
(
0 => '2014-04-04'
1 => '200'
2 => '100'
3 => '900'
)
)
The above would get you the results in $graphData. However, this would be heavy on processor for larger sets.
Here's an option:
First group all the data by dates, then convert it back into the representation you need.
If you want to automate it a bit more, you could also keep track of the IDs and add the list for the legend automatically.
var data = [
["2014-04-01", "1", "100"],
["2014-04-02", "1", "200"],
["2014-04-03", "1", "150"],
["2014-04-04", "1", "5"],
["2014-04-01", "2", "200"],
["2014-04-02", "2", "600"],
["2014-04-03", "2", "15"],
["2014-04-04", "2", "25"],
["2014-04-01", "3", "99"],
["2014-04-02", "3", "85"],
["2014-04-03", "3", "555"],
["2014-04-04", "3", "0"]
];
var groupByDate = function (data) {
var dataByDate = {};
data.forEach(function (entry) {
var date = entry[0];
var count = entry[2];
if (!(date in dataByDate)) {
dataByDate[date] = [];
}
dataByDate[date].push(count);
});
return dataByDate;
}
var toChartData = function (dataByDate) {
var chartData = [];
for (var date in dataByDate) {
chartData.push([date].concat(dataByDate[date]));
};
return chartData;
};
var byDate = groupByDate(data);
var chartData = toChartData(byDate);
chartData.unshift(['Date', 1, 2, 3]);
console.log(chartData);
Arrays can be rough for things like this, to make it easier it can be best to first convert it to an object to make it easier to work with.
var obj = {};
for(var i=0;i<data.length;i++){
if(!obj[data[i][0]]){ //check if index already exists
obj[data[i][0]] = {}; //create sub object from the index
}
for(var ii=0;ii<data[i].length;ii++){
if(ii!=0){ //since the 0 index is the parent here, ignore it
obj[data[i][0]][ii] = data[i][ii];
}
}
}
This should translate to an object like so:
var data = {
'2014-04-01':{
1:100,
2:200,
3:99
} //continue for the rest
}
So like that you can probably see that converting it into pretty much any other structure will be far easier.
var graph = [['date','1','2','3']];
for(var index in data){
if(data.hasOwnProperty(index)){
var arr = [index];
for(var index2 in data[index]){
if(data[index].hasOwnProperty(index2)){
arr.push(data[index][index2]);
}
}
graph.push(arr);
}
}
Untested and written on the spot, but the concept is there.