Immutable.js mergeDeepWith issue - javascript

I amusing Immutable.js and having problems merging an object with an array .
My fucntion for merging is:
function singleTrackReducer(state = Immutable.Map(singleTrack), action) {
switch (action.type){
case AudioFormActions.CHANGE:
return state.mergeDeepWith((prev, next) => next, action.entity);
default:
return state;
}
}
The object that I am merging to looks like this:
const singleTrack = {
songTitle: '',
mainArtists: [],
featuredArtists: [],
releaseDate: '',
primaryGenre: '',
isExplicit: false,
labelName:'',
upCode: '',
eanCode: '',
isrcCode:'',
copyRight: ''
};
I am trying to update the mainArtists property.. For example i can add several artists to my artist array and perform an update successfully. However when I delete an object from the array it appears to be filled with a previous object.
Say for example the artist Array is [drake, rihanna, tyga]
If I call the function with action entity [drake, rihanna, tyga, john] it updates fine and the mainArtists property becomes [drake, rihanna, tyga, john].
when I delete an artist example tyga and the array is [drake, rihanna, john]
the mainArtist property becomes [drake, rihanna, john, john]
Can anyone explain how I can resolve this issue

I think this code will help you understand the issue:
var Immutable = require('immutable');
console.log(
Immutable.List(['a', 'b', 'c'])
.mergeDeep(['a', 'c'])
);
// output: List [ "a", "c", "c" ]
console.log(Immutable.List(['a', 'b', 'c'])
.mergeDeepWith((prev, next) => {
console.log(`Conflict between ${prev} and ${next}.`);
return next;
}, ['a', 'c'])
);
// output: Conflict between a and a.
// Conflict between b and c.
// List [ "a", "c", "c" ]
Basically, when merging lists, items appear to be copied from one to the other at each index, and if there's already a value at that index, it's considered a conflict:
For index #0, there's "a" in the first list and "a" in the second list. We resolve the conflict by preferring the second value (though in this case they're identical). So index #0 gets "a".
Then we go to index #1 and find the first list has "b" and the second list has "c". We resolve the conflict by choosing the second value, so index #1 gets "c".
Now for index #2, we have no conflict, since only the first list has a value. We keep "c" in index #2, so the final list is "a", "c", "c".
You could instead use a set, but that basically performs a union operation, so nothing would ever be deleted:
console.log(
Immutable.Set(['a', 'b', 'c'])
.mergeDeep(['a', 'c'])
);
// output: Set { "a", "b", "c" }
I don't actually think you're looking to do a merge of this list at all... I think you simply want to copy the new value over the old value. If that's the case, maybe you're just looking for merge instead of mergeDeep:
var state = Immutable.Map({
songTitle: '',
mainArtists: [],
featuredArtists: [],
releaseDate: '',
primaryGenre: '',
isExplicit: false,
labelName:'',
upCode: '',
eanCode: '',
isrcCode:'',
copyRight: ''
});
function doMerge(state, newState) {
// no deep merge here, just copy whatever fields are present in newState
return state.merge(newState);
}
console.log(state.get('mainArtists'));
// output: []
state = doMerge(state, {
mainArtists: ['drake', 'rihanna', 'tyga']
});
console.log(state.get('mainArtists'));
// output: List [ "drake", "rihanna", "tyga" ]
state = doMerge(state, {
mainArtists: ['drake', 'rihanna', 'tyga', 'john']
});
console.log(state.get('mainArtists'));
// output: List [ "drake", "rihanna", "tyga", "john" ]
state = doMerge(state, {
mainArtists: ['drake', 'rihanna', 'john']
});
console.log(state.get('mainArtists'));
// output: List [ "drake", "rihanna", "john" ]

Related

In Javascript, after deleting key in object, rename remaining keys using sequential numbers

filters = { 1: { stat: 'a' }, 2: { stat: 'b' }, 3: { stat: 'c'} }
delete filters[1]
Filters is now 2: { stat: 'b' }, 3: { stat: 'c'} }, however we need the lowest key to equal 1, the 2nd lowest key to equal 2, and so on. In the example above, we deleted the lowest key, which requires renaming of keys. In the situation where we deleted key == 3, obviously no renaming of keys would be required.
Order matters in the sense that, in the example above, key == 2 needs to be renamed to 1, and key == 3 then needs to be renamed to 2. key == 3 cannot simply be renamed to 1.
Maybe consider using an array. The work will be a bit different, but will probably be what you want.
Note: It will start at 0, not at 1.
If you want a collection of numeric indexed keys in sequential ascending order with easy rearrangement when a value is removed - then use an array, not an object.
const filters = [{ stat: 'a' }, { stat: 'b' }, { stat: 'c'}];
filters.splice(1, 1); // remove 1 item from index 1 of the array
console.log(filters);
// if you need to use the original structure somewhere too,
// transform it when needed:
const filtersObj = Object.fromEntries(
filters.map((obj, i) => [i + 1, obj])
);
console.log(filtersObj);

How can I filter an array containing varied object structures dynamically?

My usage will contain 6 different object types (some which contain double nested arrays), and any possibility of number of entries, on the condition that an given entry is unique.
These objects do not have a consistent unique identifier (a unique identifier is applied in backend on submission).
here is an example of what the array may look like (only 2 object types):
arr = [
{name:"aaa",time:15},
{name:"aaa",time:22},
{timeline: "250", chars[{a},{b},{c}]},
{timeline: "220", chars[{d},{e},{f}]},
]
obj = {name:"aaa",time:22}
My intention is to gain a true or false based on if obj is inside arr
I have tried methods:
I was suggested this method & it errors: #<Object> is not a function
console.log(arr.find(obj))
I also found this suggestion but it will always return false even with the element present
console.log(arr.includes(object))
I tried this method myself, though it will always fail.
console.log(arr.filter((element, index) => element === obj)
With attempt 4, If I was to compare name, this would be insufficient as unique time would be ignored missing valid entries.
If I was to pass every field, this would also not work as each object may or may not have the field and cause error.
Its not really possible to manually pre-filter filter into distinct categories, as every time a new type is added it will need manually adding to the filter.
If there is a library which could do this that you know of, please let me know as that would be perfect. Otherwise any other suggestions (excluding separating arrays) Would be greatly appreciated.
Use arr.some() to check if the required object is present in the array.
To compare the objects, a simpler way is to Stringify both the Objects and compare them.
const arr = [
{name:"aaa",time:15},
{name:"aaa",time:22},
{name: "aaa", chars: ["a", "b", "c"]},
{name: "bbb", chars: ["d", "e", "f"]},
]
const obj1 = {name:"aaa", time: 15}
const obj2 = {name:"aaa",chars: ["a", "b", "c"]}
console.log(arr.some((element) => JSON.stringify(element) === JSON.stringify(obj1))) // true
console.log(arr.some((element) => JSON.stringify(element) === JSON.stringify(obj2))) // true
Didn't give much thought on performance.
I didn't put much thought on performace here but this might help:
function checkObjectInArray(arr, obj) {
const res = arr.some((el) => deepEqual(el, obj));
console.log(res);
}
function deepEqual(obj1, obj2) {
if (Object.keys(obj1).length !== Object.keys(obj2).length) return false;
for (let prop in obj1) {
if (!obj2.hasOwnProperty(prop) || obj2[prop] !== obj1[prop]) {
return false;
}
}
return true;
}
in your case you can use it like:
arr = [
{ name: "aaa", time: 15 },
{ name: "aaa", time: 22 },
{ timeline: "250", data: ["2", "3", "4"] },
{ timeline: "251", data: ["2", "3", "4"] }, // what is chars[{d},{e},{f}] ?!
];
obj = { name: "aaa", time: 22 };
checkObjectInArray(arr, obj);
Observation : arr is not a valid array. Nested chars is not containing a valid value.
Solution : You can simply achieve the requirement by Just converting the JSON object into a JSON string and by comparing.
This solution works fine as you are just trying to find a single object in the passed arr.
Live Demo :
const arr = [
{name:"aaa",time:15},
{name:"aaa",time:22},
{timeline: "250", chars: [{a: 1},{b: 2},{c: 3}]},
{timeline: "220", chars: [{d: 4},{e: 5},{f: 6}]},
];
const obj = {name:"aaa",time:22};
const res = JSON.stringify(arr).indexOf(JSON.stringify(obj)) !== -1 ? true : false;
console.log(res);

How to sort a key value pair of array in javascript

So I have this array getting fetched from firebase and I have been trying to map that array and the array is in key value pair
{
A: {name: "test1", views: "20"},
B: {name: "test2", views: "30"},
C: {name: "test3", views: "23"}
}
I want to either map them or if I can reverse this array like
{ C: {}, B: {}, A: {}}
I'm doing all this in react native so please suggest some solution to it.
If you want to just sort it alphabetically.
const unsorted = {
A: {name: "test1", views: "20"},
B: {name: "test2", views: "30"},
C: {name: "test3", views: "23"}
}
const sorted = {};
Object.keys(unsorted).sort().forEach(key => {
sorted[key] = unsorted[key];
});
or reverse alphabetically sorted one.
Object.keys(unsorted).sort().reverse().forEach(key => {
sorted[key] = unsorted[key];
});
So i was searching the web and found this
As above you guys suggested it is not an array it is an Object and can be sorted this way
let list = Object.entries(snapshot.val())
.sort(function (x, y) {
return x[1].spectators - y[1].spectators;
})
.reverse();
this is for descending order for ascending remove reverse()
Thank you!
Reversing the sequence in which keys are extracted from an object is a bit annoying because you have to take them all out and then place them back all in in the order you want:
function reverse(o) {
let entries = Object.entries(o).reverse();
entries.forEach(e => delete o[e[0]]);
entries.forEach(e => o[e[0]] = e[1]);
}
This code works by mutating the object, thus maintaining eventually references from other objects to this one valid; mutating the object is also important to maintain the correct prototype of the object if it wasn't the default. If you want to clone it instead you should be careful about copying the same prototype.

How to filter multiple properties of one array of object from the other array of object?

I am trying to solve the problem in which i have to apply multiple filters to the array of object. Let suppose I am having a larger array of object which contains the configuration property which is further an object. On other side i have small object which are the ones the user chooses to filter(based on the checkboxes). i want to compare objects made with the parent array of objects by selecting multiple values.
So in the image the user chooses multiple values(using check boxes) and based on that he needs to filter the main array of objects.So after checking the checkboxes i get childObject and i have to filter parentArray on the basis of that..... please help me with this:
childobject =
{'Bathroom': '[2,1]',
'Bedroom': '[3,2]',
'halfBathroom':'0',
'name':'[2BD-2BA,2BD-2BA-1]'}
parentArray = [
0:{},
1:{},
2:{
'property1':'____',
'property2':'_____',
'configuration':'{
bathroom: 2
bedroom: 2
created_at: "2019-03-08 20:52:52"
created_by: 264
half_bathroom: 1
id: 26
is_selected: 0
name: "2BD-2BA-1/2BA"
name_en: "2BD-2BA-1/2BA"
name_es: "2RE-2BA-1/2BA"
status: 1
updated_at: "2019-08-23 05:39:44"
}'
}
3: {},
4:{}
]
I had to update the datastructure at some points:
You had different key in child and parent (upper/lowercase + camelcase/_ writing)
Some Missing } in the parent.
In child quotationmarks for integer deleted.Missing , added.
Changing some values in cruiteria, so that there is a result.
In parent delting of 0:, 1:, 2:, 3:, 4: to get a valid array.
childArray = {
'bathroom': [2,1],
'bedroom': [3,2],
'half_bathroom':1,
'name':['2BD-2BA', '2BD-2BA-1/2BA']
};
parentArray = [
{},
{},
{
'property1':'____',
'property2':'_____',
'configuration':{
bathroom: 2,
bedroom: 2,
created_at: "2019-03-08 20:52:52",
created_by: 264,
half_bathroom: 1,
id: 26,
is_selected: 0,
name: "2BD-2BA-1/2BA",
name_en: "2BD-2BA-1/2BA",
name_es: "2RE-2BA-1/2BA",
status: 1,
updated_at: "2019-08-23 05:39:44"
},
},
{},
{}
]
let res = parentArray.filter(elem => Object.entries(childArray).every(([key,val]) => {
let conf = elem.configuration;
if (conf===undefined) return false;
if (typeof(val) === 'object') {
return val.some(crit => crit===conf[key]);
} else {
return val===conf[key];
}
}));
console.log(res);

Removing Duplicates in Arrays

I am trying to pass a function that removes duplicates from an array. It should handle strings, object, integers as well. In my code so far I am showing that it will handle strings but nothing else. How can Imake this function universalto handle numbers,handle arrays,handle objects, and mixed types?
let unique = (a) => a.filter((el, i ,self) => self.indexOf(el) ===i);
In this function I hav unique() filtering to make a new array which checks the element and index in the array to check if duplicate. Any help would be appreciated.
i think the first you should do is to sort the array ( input to the function ). Sorting it makes all the array element to be ordered properly. for example if you have in an array [ 1, 3, 4, 'a', 'c', 'a'], sorting this will result to [ 1 , 3 , 4, 'a', 'a' , 'c' ], the next thing is to filter the returned array.
const unique = a => {
if ( ! Array.isArray(a) )
throw new Error(`${a} is not an array`);
let val = a.sort().filter( (value, idx, array) =>
array[++idx] != value
)
return val;
}
let array = [ 1 , 5, 3, 2, "d", "q", "b" , "d" ];
unique(array); // [1, 2, 3, 5, "b", "d", "q"]
let obj = { foo: "bar" };
let arraySize = array.length;
array[arraySize] = obj;
array[arraySize++] = "foo";
array[arraySize++] = "baz";
array[arraySize++] = obj;
unique(array); // [1, 2, 3, 5, {…}, "b", "baz", "d", "foo", "hi", "q"]
it also works for all types, but if you pass in an array literal with arrays or objects as one of its element this code will fail
unique( [ "a", 1 , 3 , "a", 3 , 3, { foo: "baz" }, { foo: "baz" } ] ); // it will not remove the duplicate of { foo: "baz" } , because they both have a different memory address
and you should also note that this code does not return the array in the same order it was passed in , this is as a result of the sort array method
Try using sets without generics. You can write a function as
Set returnUnique(Object array[]) {
Set set=new HashSet();
for (Object obj:array) {
set.add(obj);
}
return set;
}

Categories