Creating array with spread operator - javascript

Here is a javascript arrow function I found in a React book:
const createArray = (length) => [...Array(length)];
Why not simply return a new array?
const createArray = (length) => Array(length);
If I log the result of createArray(7) with either of the definitions, I get the same result:
(7) [undefined, undefined, undefined, undefined, undefined, undefined, undefined]
What does the first definition achieve as compared to the second one?

Array(length); will create a sparse array - one with no own-properties (except length), which cannot be iterated over with the array iteration methods:
const arr = new Array(7);
console.log(arr.hasOwnProperty('4'));
arr.forEach(() => {
console.log('iteration');
});
In contrast, utilizing spread syntax will populate the new array properly:
const arr = [...new Array(7)];
console.log(arr.hasOwnProperty('4'));
arr.forEach(() => {
console.log('iteration');
});

Both ways of creating an array are different. They do not produce the same result.
Second way of creating an array will create a sparse array with only length own property and no index properties. You can see this using Object.getOwnPropertyNames()
const arr = new Array(5);
console.log(Object.getOwnPropertyNames(arr));
Using the spread syntax will create an array will index properties as shown in the following code example:
const arr = [...new Array(5)];
console.log(Object.getOwnPropertyNames(arr));

i hope if you want its example here.
More Information = > https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
const testArr = [
{ name: false, expected: false },
{ name: null, expected: false },
{ name: undefined, expected: false },
{ name: "", expected: false },
{ name: " \t\n", expected: false },
];
const createArray = (arr) => { return [...arr]}
console.log(createArray(testArr))

Related

How to copy a variable arrray from another arrray in javascripts

I have an array as below:
const arr = [
{
title: 's4',
value: '124'
},
{
title: 's2',
value: '121'
},
{
title: 's3',
value: '122'
}
];
and I want to create a new another array copy from the old array same as below:
const arrCopy = [
{
value: '124'
},
{
value: '121'
},
{
value: '122'
}
];
then my code as below:
var arrCopy = [...arr,arr.value]
but it has a problem, so anyone help me, thanks.
Just as in the comment above you can use awesome Javascript functions, in this case, you would like to use the map function of your array to map every item of the array as you like.
const arrayMapped = yourArray.map(item => {
value: item.value
})
Here is another way using Javascript Destructuring, you just ask with properties would you like from the JS Object, in this case, you just like the value property.
const arrayMapped = yourArray.map(( { value } ) => ( { value } ))
How Array.map works
How Object Destructuring works
You can simply use Array.map, as it returns a new array with the required value.
const newArr = arr.map(element => ({ value: element.value }))
console.log(newArr);
For references : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
If you are allowed to import a library. Ramda has a lot of functions to work with arrays.
For your specific question, project would do the job.
import R from "ramda";
R.project(["value"], arr) //return equals arrCopy

ES6 way - Get unique values from a nested array by key

trying to improve my JS chops.
Is there a cleaner way to retrieve the property value from the array below, by key, from a nested object, removing duplicates and sorting them alphabetically?
Here's what I have:
getObjectValues(array, key){
var unique = [];
array.forEach(function(item){
item[key].forEach(function(value){
if (unique.indexOf(value) < 0) {
unique.push(value)
}
})
});
return unique.sort();
},
example array of object:
[
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']}
]
expected output should be an array:
var array = ['a','b','c']
You could just use a Set, and add all the items to it:
let arr = [
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']},
{ name: 'hello', value: ['a','b','c']}
]
console.log(
Array.from(
new Set(
arr.reduce(
(carry, current) => [...carry, ...current.value],
[]
)
)
).sort()
)
If you need something concise, you may go as simple as that:
make use of Set to get rid of duplicates
employ Array.prototype.flatMap() (with slight touch of destructuring assignment) to extract value items from within all objects into single array
const src = [{name:'hello',value:['c','b','d']},{name:'hello',value:['e','b','c']},{name:'hello',value:['f','a','e']}],
result = [...new Set(src.flatMap(({value}) => value))].sort()
console.log(result)
.as-console-wrapper{min-height:100%;}
If you need something really fast, you may do the following:
use Array.prototype.reduce() to turn your array into Set of unique records (looping through value items with Array.prototype.forEach and doing Set.prototype.add())
spread resulting Set into array and .sort() that
const src = [{name:'hello',value:['c','b','d']},{name:'hello',value:['e','b','c']},{name:'hello',value:['f','a','e']}],
result = [...src.reduce((acc,{value}) =>
(value.forEach(acc.add, acc), acc), new Set())].sort()
console.log(result)
.as-console-wrapper{Min-height:100%;}

flatten an array of objects, while also considering for uniqueness

I have the following array of objects.
var array = [
{
name: 'abc',
place1: 'def'
},
{
name: 'abc',
place2: 'ghi'
}]
I am trying to get the following output
var array = [[name:'abc'],[place1:'def'],[place2:'ghi']]
this is my attempt:
let arr = []
array.forEach((element,index) => {
const keys = Object.keys(element)
keys.forEach(e => {
let temp = [];
temp[0] = e;
temp[1] = element[e];
if(!arr.indexOf(temp)
arr.push(temp)
});
});
but I am not getting the expected output.
I'm not sure how a an array of objects with different properties would help you. You should probably use one object with all properties or an array of entries.
However, to get the result you want - merge the array of objects to a single object by spreading into Object.assign() to remove duplicates. Then convert to an array of entries [key, value], and map back to an array of objects:
const array = [{"name":"abc","place1":"def"},{"name":"abc","place2":"ghi"}]
const result = Object.entries(Object.assign({}, ...array))
.map(([k, v]) => ({ [k]: v })) // remove the map to get an array of entries
console.log(result)

Filter an empty array from a parent array

How can I completely remove an empty array from a parent array, before adding a new element.
I have a structure that looks like this
var parentArray = [ ['123', '345'], [], ['12'] ]
I want to remove array at index 1 before adding a new array.
I have tried this but it doesn't remove it:
parentArray.filter((array, index) => {
if (array.length === 0) {
parentArray.splice(index, 1);
}
})
parentArray.push(['435']);
console.log(parentArray); //Still give [["123", "345"], [], ["12"]]
You should not mutate your array in the filter method.
The callback function should return true if you want to keep the item, false if not.
const parentArray = [['123', '345'], [], ['12']];
const filteredArray = parentArray.filter( item => item.length !== 0);
console.log(filteredArray)
No need lodash or 3rd part libraries, here is what actually you needed,
var numbers = [ ['123', '345'], [], ['12'] ]
result = numbers.filter(x => x.length > 0);
console.log(result);
Use _.filter for that:
parentArray = _.filter(parentArray, function (array) {
return array.length > 0;
})
Ok, First of all as said above don't mutate any iterable while iterating through it.
and Array.filter returns a new array based on the condition given and it won't change the array on which it is being called.
if you want to keep the original parentArray and create a new array without the empty arrays in the parrentArray then do the following
let parentArray2 = parentArray.filter(e=>e.length !== 0)
this will give you the new array referenced by parentArray2 which will be
[ [ '123', '345' ], [ '12' ] ]
and parentArray remains as it is and then you can push a new array into parentArray2
if you don't want to retain the original parentArray then do the following
parentArray = parentArray.filter(e=>e.length !== 0)
the parent array will be initialized with a new array [ [ '123', '345' ], [ '12' ] ]
and then you can push any element are array or object into the parentArray
You can use lodash's _.reject() with _.isEmpty().
Reject removes an item if the predicate returns true, and isEmpty returns true for empty arrays.
var parentArray = [ ['123', '345'], [], ['12'] ]
var result = _.reject(parentArray, _.isEmpty)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Without lodash, you can use Array.filter(), and just return the length. Because 0 is falsy, and the item would be removed:
const numbers = [ ['123', '345'], [], ['12'] ]
const result = numbers.filter(o => o.length)
console.log(result)
The following code keeps the items which are not empty and stores them inside result.
const result = _.filter(parentArray, (item, i) => {
return !_.isEmpty(item);
});
console.log(result);

ReactJS Spread Operator

I am using React.
I have an array of objects in my state.
this.state = {
team: [{
name:'Bob',
number:23
},
{
name:'Jim',
number:43
}]
}
When I try to make a copy of the array to change a object's property, I don't get the results I want.
I have tried:
let tempTeam = [...this.state.team]
Any change to tempTeam also mutates this.state.team
AND
let tempTeam = this.state.team.map(player => return {...player})
This just throws an error, it doesn't like {...player}
How can I get the array of objects without it referencing this.state.team?
You have a syntax error in the posted code. If you change it to:
let tempTeam = this.state.team.map(player => ({...player}));
Or:
let tempTeam = this.state.team.map(player => {
return { ...player };
});
You will get a new array with the same object values without the references.
Object.assign and spread syntax create shallow copies. If you mutate a nested property in the copied one you also mutate original object.
Most of the time we use map, filter, slice to get a new array by using the original one. But, even using those methods, we should not mutate the properties directly, we should return again new ones using Object.assign or spread syntax again.
As explained you have a syntax error in your code, if you fix it you can get the new array. But, most of the time you will do operations like these:
const state = {
team: [{
name:'Bob',
number:23
},
{
name:'Jim',
number:43
}]
};
const changeAll = state.team.map( player => ({
...player, number: player.number + 1,
}));
// or
const playerTheOne = state.team.filter(player => player.number === 23);
const notPlayerTheOne = state.team.filter(player => player.number !== 23);
// or
const changeJustOne = state.team.map( player => {
if ( player.number === 23 ) {
return { ...player, name: "Joe" };
}
return player;
});
console.log( state.team );
console.log( changeAll );
console.log( playerTheOne );
console.log( notPlayerTheOne );
console.log( changeJustOne );
As you can see, you don't create a new array then mutate it, you are mutating it while you are creating it.
Using Array.slice() creates a clone, so this should should work:
let tempTeam = this.state.team.slice();

Categories

Resources