MDN references JavaScript's Set collection abstraction. I've got an array of objects that I'd like to convert to a set so that I am able to remove (.delete()) various elements by name:
var array = [
{name: "malcom", dogType: "four-legged"},
{name: "peabody", dogType: "three-legged"},
{name: "pablo", dogType: "two-legged"}
];
How do I convert this array to a set? More specifically, is it possible to do this without iterating over the above array? The documentation is relatively lacking (sufficient for instantiated sets; not for conversions - if possible).
I may also be thinking of the conversion to a Map, for removal by key. What I am trying to accomplish is an iterable collection that can be accessed or modified via accessing the elements primarily via a key (as opposed to index).
Conversion from an array to the other being the ultimate goal.
Just pass the array to the Set constructor. The Set constructor accepts an iterable parameter. The Array object implements the iterable protocol, so its a valid parameter.
var arr = [55, 44, 65];
var set = new Set(arr);
console.log(set.size === arr.length);
console.log(set.has(65));
See here
If you start out with:
let array = [
{name: "malcom", dogType: "four-legged"},
{name: "peabody", dogType: "three-legged"},
{name: "pablo", dogType: "two-legged"}
];
And you want a set of, say, names, you would do:
let namesSet = new Set(array.map(item => item.name));
By definition "A Set is a collection of values, where each value may occur only once." So, if your array has repeated values then only one value among the repeated values will be added to your Set.
var arr = [1, 2, 3];
var set = new Set(arr);
console.log(set); // {1,2,3}
var arr = [1, 2, 1];
var set = new Set(arr);
console.log(set); // {1,2}
So, do not convert to set if you have repeated values in your array.
const categoryWithDuplicates =[
'breakfast', 'lunch',
'shakes', 'breakfast',
'lunch', 'shakes',
'breakfast', 'lunch',
'shakes'
]
const categoryWithoutDuplicates =[...new Set(categoryWithDuplicates)];
console.log(categoryWithoutDuplicates)
Output: [ 'breakfast', 'lunch', 'shakes' ]
What levi said about passing it into the constructor is correct, but you could also use an object.
I think what Veverke is trying to say is that you could easily use the delete keyword on an object to achieve the same effect.
I think you're confused by the terminology; properties are components of the object that you can use as named indices (if you want to think of it that way).
Try something like this:
var obj = {
"bob": "dole",
"mr.": "peabody",
"darkwing": "duck"
};
Then, you could just do this:
delete obj["bob"];
The structure of the object would then be this:
{
"mr.": "peabody",
"darkwing": "duck"
}
Which has the same effect.
var yourSetAsArray = Array.from(new Set([1, 2, 2, 3, 3, 4, 4]));
// returns [1, 2, 3, 4]
Related
I understand the below code adds a new object to an array of objects but fuzzy on a specific syntax: setProductList([array, obj])
From what I'm seeing, the setProductList function takes in an object. That object consists of an array and an object. So how does it add the object to the array? is this built into JS or React?
// array of products
const Products = [
{
item: "basketball",
price: 3,
description: "basketball desc",
},
{
item: "football",
price: 5,
description: "football desc",
},
];
// setting state
const [productList, setProductList] = useState(Products);
// handling click
const handleClick = () => {
// Don't quite understand the syntax of below block
setProductList([
...productList, // spread creates a copy of the array
{
item: "baseball",
price: 4,
description: "baseball desc",
},
]);
};
What you are seeing is Spread operator (...)
Spread syntax can be used when all elements from an object or array need to be included in a list of some kind.
By writing [ (element inside) ], you did create a new array. ...productList alone does not create a new array
You could understand ...productList as it helps you write shorter code, instead of writing like this
setProductList([
productList[0],
productList[1],
// ...
productList[productList.length - 1],
{
item: "baseball",
price: 4,
description: "baseball desc",
},
])
Another example that could help you understand the spread operator, is the use of Math.max. Basically, syntax of Math.max is Math.max(value0, value1, ... , valueN).
For example you have an array of N elements, because Math.max solely could not take an array as arguments, so to calculate max of the array, you could iterate each element and compare
const arr = [1, 3, 2]
let max = -Infinity
for (const num of arr) {
max = Math.max(max, num)
}
console.log(max)
But now with spread operator, you could achieve the same result in a shorter way
const arr = [1, 3, 2]
let max = Math.max(...arr)
console.log(max)
This feature is built into js and called Object Spreading
Example
var x = [1, 2] // an array
console.log(x)
// spreads an array, and put an extra element
var y = [...x, 6]
console.log(y)
so, the state hook returns a function here - setProductList
That just updates the state to the new array.
it's a common practise. See this detailed answer for in deth explanation
Ok, the code which you don't understand basically is setting a new copy of the current array, BUT including the new element (it'd be like push a new element in the array. BUT push would modify the original array. In this case, it's making a copy and pushing the value to that new array)
Lets go line by line.
We have:
setProductList([
...productList,
{
item: "baseball",
price: 4,
description: "baseball desc",
},
]);
We will define:
setProductList([ // Line 0
...productList, // Line 1
{ // Line 2
item: "baseball", // Part of Line 2
price: 4, // Part of Line 2
description: "baseball desc", // Part of Line 2
}, // Part of Line 2
]); // Part of Line 1(]) & 0())
With Line 0 (setProductList) we are setting a new value to productsList because react hooks and useState. (https://reactjs.org/docs/hooks-state.html)
With Line 1 we are creating a new copy of the array ([...oldArray]) will return a copy of the previous array (You can read: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax)
With Line 2, we are including a new value at the end of the new array.
I guess your confusion comes from not understanding the spread syntax.
Spread in array literals
A more powerful array literal
Without spread syntax, to create a new array using an existing array
as one part of it, the array literal syntax is no longer sufficient
and imperative code must be used instead using a combination of
push(), splice(), concat(), etc. With spread
syntax this becomes much more succinct:
let parts = ['shoulders', 'knees'];
let lyrics = ['head', ...parts, 'and', 'toes'];
// ["head", "shoulders", "knees", "and", "toes"]
Just like spread for argument lists, ... can be used anywhere in the
array literal, and may be used more than once.
When looking at your code:
setProductList([
...productList, // spread creates a copy of the array
{
item: "baseball",
price: 4,
description: "baseball desc",
},
]);
The statement "spread creates a copy of the array" is incorrect. The spread operator by itself does not create a copy. It takes the items in an iterable (like an array) and and places them in the context as separate arguments/elements.
[...productList]
The above would create a copy because we define a new array and place all the items of productList in this new array. Thus creating a copy.
[...productList, newItem]
Defines a new array, places all the items of productList in this new array and places newItem behind it. Since we added newItem it strictly speaking is not really a copy.
I'm wondering if there is a way to clear or empty an array of objects, let's say for example i have this array of objects, which i borrow from firebase firestore, i do this with a snapshot, here is the code:
let siteButtonsData = firebase.firestore()
.collection('app_settings')
.doc('dashboard')
.collection('main_panel')
.onSnapshot(doc => {
doc.forEach(doc => {
this.arrObj.push(doc.data())
});
})
Then my array of objects is populated correctly, and it's shown like this:
data() {
return {
arrObj: [
{
action: 'one',
id: 1,
text: 'hello1'
},
{
action: 'two',
id: 2,
text: 'hello2'
},
{
action: 'three',
id: 3,
text: 'hello3'
},
]
}
}
With v-for i iterate over this.buttons to create some dynamic content in my app, but when something changes on my firestore database, and the snapshot updates it, i got duplicates, i was hoping to clear the array of objects before updating from firestore, so i would have no duplicates, but it's not working, so far i have tried:
this.arrObj = [{}]
this.arrObj = [] //This option leaves me with no way to push the array of objects
this.arrObj.length = 0
No matter which of this methods i use, i can't update correctly the array of objects, the first time it does the job well gathering the data from firestore, but once i update the database i got duplicates.
thanks in advance for any help or hint
When working with arrays you always need to make sure that Vue's reactivity system is catching the changes and updates the view. Vue is automatically observing some array mutation methods to make sure to update, them being push(), pop(), shift(), unshift(), splice(), sort() and reverse().
See https://v2.vuejs.org/v2/guide/list.html#Mutation-Methods
As for your example, what should work is then:
let siteButtonsData = firebase.firestore()
.collection('app_settings')
.doc('dashboard')
.collection('main_panel')
.onSnapshot(doc => {
this.arrObj.splice(0, this.arrObj.length);
// I would think this works as well:
// this.arrObj = [];
doc.forEach(doc => {
this.arrObj.push(doc.data())
});
})
What if you want to empty an entire array and just dump all of it's elements?
There are a couple of techniques you can use to create an empty or new array.
The simplest and fastest technique is to set an array variable to an empty array:
var ar = [1, 2, 3, 4, 5, 6];//do stuffar = [];//a new, empty array!
The problem this can create is when you have references to the variable. The references to this variable will not change, they will still hold the original array's values. This of course can create a bug🐛.
This is an over simplified example of this scenario:
var arr1 = [1, 2, 3, 4, 5, 6];var arr2 = arr1; // Reference arr1 by another variable arr1 = [];console.log(arr2); // Output [1, 2, 3, 4, 5, 6]
A simple trick to clear an array is to set its length property to 0.
var ar = [1, 2, 3, 4, 5, 6];console.log(ar); // Output [1, 2, 3, 4, 5, 6]ar.length = 0;console.log(ar); // Output []
Another, sort of unnatural technique, is to use the splice method, passing the array length as the 2nd parameter. This will return a copy of the original elements, which may be handy for your scenario.
var ar = [1, 2, 3, 4, 5, 6];console.log(ar); // Output [1, 2, 3, 4, 5, 6]ar.splice(0, ar.length);console.log(ar); // Output []
The last two techniques don't create a new array, but change the array's elements. This means references should also update.
There is another way, using a while loop. It feels a little odd to me, but at the same time looks fancy, so it may impress some friends!
var ar = [1, 2, 3, 4, 5, 6];console.log(ar); // Output [1, 2, 3, 4, 5, 6] while (ar.length) { ar.pop(); }console.log(ar); // Output []
Not a way I would go about clearing a JavaScript array, but it works and it is readable. Some performance test have also shown this to be the fastest technique, so maybe it is better than I originally thought!
I have an object called featureSet.
Inside of featureSet there are many items, including an array called features, which contains other array, attributes.
I can add a new array inside of featureSet.features.attributes by doing the following within a for loop
featureSet.features[i].attributes.NEWITEM= [NEWITEM_ARRAY];
And when I use console.log(featureSet), I can see that the items are there.
When I use var test = JSON.stringify(featureSet), however, only the original featureSet is returned.
How can I circumvent this so that when I call JSON.stringify, the new items are there as well?
Thank you in advance.
I guess what you do is close to:
let arr = []
console.log(arr) // []
arr.push(1)
console.log(arr) // [1]
arr.abc = 2
console.log(arr.abc) // 2
arr.push(3)
console.log(arr) // [1, 3]
console.log(JSON.stringify(arr)) // '[1, 3]'
console.log(arr.abc) // 2
JSON.stringify loops through array props with the help of Symbol.iterator. Your properties do not have positive integer indexes, that's why they are ignored. There is an example on MDN as well: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
One more example to consider (continues the one above):
arr[7] = 7
console.log(arr) // [1, 3, undefined, undefined, undefined, undefined, undefined, 7]
console.log(JSON.stringify(arr)) // "[1,3,null,null,null,null,null,7]"
How can I circumvent this so that when I call JSON.stringify, the new items are there as well?
You are trying to append attributes to an array, which will not work.
You can only append attributes to an object.
/* the original feature set */
const featureSet = {
features: [
{feature: 'color',
attributes: {}}, // this is an object, not an array
{feature: 'shape',
attributes: []} // this is an array as per original scenario
]
}
/* adding attributes to an object succeeds */
featureSet.features[0].attributes.NEWITEM = ['this', 'was', 'appended'];
/* adding attributes to an array quietly fails */
featureSet.features[1].attributes.NEWITEM = ['this', 'was', 'not', 'appended'];
const featureSetAsJSONString = JSON.stringify(featureSet)
console.log(featureSetAsJSONString) // notice that feature[0] is as expected, but [1] isn't
Hope this helps.
Cheers,
Try this
featureSet.features[i].attributes.push({NEWITEM: [NEWITEM_ARRAY]})
Ramda remove : Ramda Repl link
The following is the given example, it removes specific numbers from an Array:
R.remove(2, 3, [1,2,3,4,5,6,7,8]); //=> [1,2,6,7,8]
Now I created an Array of objects, one being empty:
var objArray = [{id: 1, name: 'Leon'},{id: 2, name: 'Paulo'},{}];
When I try:
R.remove({}, objArray);
or
R.remove(R.isEmpty, objArray);
It returns a function:
Why would that be you suppose?
Figured it out:
const filteredAlerts = R.filter(Util.notEmpty, res.alerts);
I needed to filter by objects that are NOT empty.
This is my Util.notEmpty function:
const notEmpty = R.compose(R.not, R.isEmpty);
Or can it? This may sound like a dumb question... and I'm really hoping it is because my initial Googling about lead me to believe that there is no simple way to copy an object in JavaScript.
Say you have the following:
var allFood = ['fish', 'greens', 'fruit', 'candy', 'soda', 'cookies'];
var moreFood = allFood;
var diffFood = allFood;
moreFood.splice(3, 0, "grain", "juice");
diffFood.splice(3, 3, "tacos", "meat");
document.write(allFood + "<br/>");
document.write(diffFood);
Now they all equal "fish,greens,fruit,tacos,meat,soda,cookies" which is annoying, for lack of a better word.
Could you explain why JavaScript has this limitation?
And yeah, I read this: What is the most efficient way to deep clone an object in JavaScript? which seems a little cumbersome and actually failed when I tried it with the above example...
For your specific example, i.e. for arrays with simple elements, the slice method can do it:
var allFood = ['fish', 'greens', 'fruit', 'candy', 'soda', 'cookies'];
var moreFood = allFood.slice();
var diffFood = allFood.slice();
This method creates a so-called shallow copy of the array. So it does the job for arrays with primitives, such as strings, numbers and booleans.
If an array element is an object, that object reference is copied, and so the arrays share the original object:
var a = [{x: 1}];
var b = a.slice();
// both arrays reference the same object:
console.log(a[0] === b[0]); // output: true
// so...
b[0].x = 2;
console.log(a[0].x); // output: 2
You can read about Javascript's pass-by-reference and pass-by-value behaviour here.
For cloning javascript object you can use lodash library.
var allFood = ['fish', 'greens', 'fruit', 'candy', 'soda', 'cookies'];
var moreFood = lodash.cloneDeep(allFood);
Now changes you make to allFood wouldn't affect moreFood and vice versa.
A simple way to clone objects available in es6, though current supported by most browsers is Object.assign
var original = [1, 2, 3];
var copy = [];
Object.assign(copy, original);
copy.push(2);
//=> [1, 2, 3, 2]
console.log(original);
// => [1, 2, 3];