Iterate over array of object using map till the second last object - javascript

I am having an array of objects where all objects have the same keys except the last object. Think like array have values and to denote all these values as a whole I have a key I am pushing the key at last along with the values in the array.
homeTask is a list of object which is the values and homeTaskKey is the key to represent the homeTask
res.data.resultSet.homeTask.forEach(element => {
var singleEvent={
task:'',
taskDuration:'',
status:'',
};
singleEvent.task=element.task;
singleEvent.taskDuration=element.taskDuration;
singleEvent.status=element.status;
newEvents.push(singleEvent);
});
newEvents.push(res.data.resultSet.homeTaskKey);
addEvent(newEvents);
}
addEvent is props method of parent component where I am setting the array to state variable name as events which is array type.
When I iterate over events using map I want to skip the last object since it does not have keys like task, taskDuration and status. Therefore it won't give any problem when I fetch those values.

events.slice(0, events.length-1).map(<function>);
this will ignore the last element and all n-1 entries will be fed to map
UPDATE:
the array name is events not event therefore it should be events.length

You could still use map, but simply pop the last element off once the map completes. For example:
const newEvents = homeTask.map(({ task, taskDuration, status }) => ({
task, taskDuration, status
}))
newEvents.pop()
addEvent(newEvents)
Or just replace the last item with your taskkey, as you know the last item will be junk:
newEvents[newEvents.length - 1] = res.data.resultSet.homeTaskKey
Or just slice the array prior to mapping, and then push the taskKey at the end like you were doing. slice is safe to perform on your prop, as it shallow copies.
Or most importantly, ask yourself why you have this entirely weird data structure that has the key appended on the end. Perhaps rethink your data and not create this problem for yourself in the first place.

res.data.resultSet.homeTask.forEach((element,index) => {})
second param to function is index you, can use this to identify the second last element by comparing it with total length of array.

hmm you can try with this
res.data.resultSet.homeTask.forEach(element => {
if(!element.task)
return false;
...bla bla bla
}

The map() method creates a new array with the results of calling a function for every array element.
So it creates an array of same length from source array.
What you need is filter()
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
Something like this;
const tasks = res.data.resultSet.homeTask.filter((element) => {
const { task, taskDuration, status } = element;
return task && taskDuration && status;
});

Related

Issue when splicing array of objects

I have a vue application that gets a set of objects from an external REST API.
In a component, I sort and filter the object into an array of objects based on a field called rank, like this:
let myResults = _.orderBy(this.search_result, 'rank', 'desc').filter(service => (service.rank >= 5) ? service: "");
I then need to move a single element/object to the end of the list before rendering it, however, when I tried to do this:
let index = myResults.findIndex(e => e.name === 'Target Element');
myResults.push(myResults.splice(index,1));
It didn't work; It pushed an empty element back to the list. Eventually, I got it working by doing the following:
myResults.push(myResults.splice(index,1)[0]);
I noticed the splice was creating an array that looked like [object, object] with all the target object in the zero index object.
I don't really understand why this happened. Have I done something to the original object somewhere or is this a vue thing?
JavaScript Array.prototype.splice() returns an Array.
Return value
An array containing the deleted elements.
If only one element is removed, an array of one element is returned.
If no elements are removed, an empty array is returned.
Since an Array is returned, you're .push()-ing and Array into an existent array. As you noticed correctly, you need to extract that one Object using removedItems[0], making
myResults.push(myResults.splice(index,1)[0]);
or equally
// Remove from array 1 item
const removedItems = myResults.splice(index, 1); // Array of removed items
// Get the first Object from array
const item = removedItems[0]; // Object
// Append one Object
myResults.push(item);
the correct approach.

Why push does not working with set methond in Map object

So very quick question here which I wasn't able to get sorted when searching google.
I have some code that works which has a Map object this.tweet and a (key,value) of (string,array). I push a value into the array and re-set Map object.
const newTweet = this.tweet.get(tweetName) || [];
newTweet.push(time);
this.tweet.set(tweetName, newTweet);
However, I am a minimalist freak and want a one-liner. When I want to add something to the array, I was wondering why I am not able to do this
this.tweet.set(tweetName, newTweet.push(time));
I keep getting a newTweet.push(time) is not a function error.
Thanks
Look at some documentation for push
The push() method adds one or more elements to the end of an array and returns the new length of the array.
Since you want to pass the array to set you can't use the return value of push.
You could create a completely new array instead:
const newTweet = this.tweet.get(tweetName) || [];
this.tweet.set(tweetName, [...newTweet, time]);

Is there a way to access to an index value while iterating over a Map object in javascript?

In my project I had to convert a Javascript Object into a Map object called mapResults. After some transformations (slicing out the first two values) I now want to iterate over this collection to render some list items with the following syntax.
{key1}:{value1}
{key2}:{value2}
The thing is that I also have an array called resultsKey with strings that I want to use as {keys} for every list item. So, lets say that my Map object and my strings array look like this:
mapResults =
0: gameStatus -> "You Won!"
1: difficulty -> "Intermediate"
2: movesCount -> 13
resultsKey = [
"Final result",
"Level",
"Number of movements",
]
Now I would like to iterate over both collections to get the desired list item output as:
Final result : You Won!
Where every key of the list item its taken from my resultsKey array and every value is taken from my mapResults object. Both collections are the same length/size.
I know that if I had an Object object (name it objectResults)instead of a Map object, I could achieve this by calling Object.keys() on the Object, and then calling .map() or forEach() on the resulting array (lets call it objectResultsKeys) like this:
objectResultsKeys.map((key, index)=>{
return <li>
{resultsKey[index]}:{objectResults[key]}
</li>
})
The thing here is, that if I had this situation I would be able to use the index parameter that the .map() function provides to access the resultsKey strings array and obtain the value I want. But there is no such thing when it comes to iterating over Map objects.
So what I want to know is if there is any solution that provides me with and index value that I can use to access my strings array while iterating over the Map object. Or if there is any other solution to achieve a similar outcome to what I've explained. Im constrained to use a Map object for this solution.
You could just take a counter:
let index = 0;
for(const [key, value] of map.entries()) {
// ...
index++;
}
Or you turn the entries into an array:
[...map.entries()].forEach(([key, value], index) =>
//...
);
But actually as Maps are ordered by insertion time I would not rely on the Maps order.

How to remove objects with the same key and value pair in arrays

I've looked through many stack overflow questions, but none seem to quite answer my question. I have an array of objects, which I would like to reduce by deleting all objects where the key and value are the same.
So my array of objects would be:
[{a:1},{a:2},{c:3},{b:1},{a:1},{c:3},{c:4},{a:1}]
The end result should be:
[{a:1},{a:2},{c:3},{b:1},{c:4}]
I've tried using filer and map, but I can only get the first object in the array, rather than all the objects that have different key/value pairs in the array. I've also tried using filter and findIndex, but with the same problem.
I also can't filter the objects before pushing them into the array.
Can someone point me in the right direction?
You can compare the two items using JSON.stringify(). We then add to a new array using reduce, if it is in the array we don't add it otherwise we do add it.
const array = [{a:1},{a:2},{c:3},{b:1},{a:1},{c:3},{c:4},{a:1}]
let unique = array.reduce((res, itm) => {
// Test if the item is already in the new array
let result = res.find(item => JSON.stringify(item) == JSON.stringify(itm))
// If not lets add it
if(!result) return res.concat(itm)
// If it is just return what we already have
return res
}, [])
console.log(unique)
Alternatively you could use a Set (as Fissure King metions) to make a unique list of items like this:
const array = [{a:1},{a:2},{c:3},{b:1},{a:1},{c:3},{c:4},{a:1}]
let unique = [...new Set(array.map(itm => JSON.stringify(itm)))].map(i => JSON.parse(i))
console.log(unique)
Assuming that all your object are of different types(different properites) and are not complex in nature i.e., not nested objects..
Create a array list(which will act as multi dimensional array).
let uniqueArr = [];
Loop through your array which contains duplicates with Arr.forEach();
Get property of the object using
Object.getPropertyNames(item);
Check wether this type of object type already exists in your uniqueArr ,if not add the property type.
uniqueArr.push({property:[]});
If the property already exists in the uniqueArr, check whether the current property value exits in the property array inside uniqueArr.
If the property doesn't not exist add the new property to the respective property array.if the property exits skip and run the loop for next object.
Once loop completed, create resultArr with the help of the
uniqueArr.
Sample : uniqueArr [ {a:[1,2]}, {b:[1]}, {c:[3]} ];
var a = [{a:1},{a:2},{c:3},{b:1},{a:1},{c:3},{c:4},{a:1}];
var newData = [];
a.map(ele=>JSON.stringify(ele)).forEach(ele=>{
if(newData.indexOf(ele) === -1){
newData.push(ele)
}
});
newData.map(ele=>JSON.parse(ele))
console.log(newData);

Immutability in a for in loop when adding an object to an array

I have a for of with a for in loop inside it, that gets a result from a Neo4J database. Using Object.assign, I take the result object and assign a property from it to a new object. My understanding is this is immutability.
I then want add the new result object to an array for reach result returned.
I can declare an empty array outside the loop and use Array.concat to create new array for each iteration. Another option could be to use Array.push. Neither of these feel immutable because I am either pushing to an array, or overwriting a variable.
Is there a way to end up with a results array, of all object, that is immutable?
let results = []
for (const row of argsArray) {
for (const key in row) {
const neo4jPropInUse = await neo4j.session(null, cypher.ngp(key, row[key]))
if (neo4jPropInUse.length !== 0) {
console.log('IN USE DETECTED')
const thingResult = Object.assign({}, {
[thingSerialNumber]: neo4jPropInUse[0].get(`RESULT`).properties[thingSerialNumber],
key: key
})
results = results.concat([thingResult])
}
}
}
Even if you declare an object with const you can still modify its contents, you just can't reassign it anymore. If your goal is to return an unmodifiable array after the loops are finished you can use Object.freeze which will stop you from modifying the object (shallowly).
Object.freeze(results);
Now it will throw an error if you try to push or pop from that array. Note that this is a "shallow freeze" and you will still be able to modify any values inside objects that are part of the array. Hope this helps.

Categories