How to add list to list in Immutable.js? - javascript

What is the best way to add List to List in Immutable.js?
concat method is working, but another way is not working.
const a = fromJS([
{
comment: 'aaaa',
who: 'a1',
buttonInfo: ['a', 'b', 'c'],
},
{
comment: 'bb',
who: 'a2',
buttonInfo: ['a', 'b', 'c'],
},
]);
const b = fromJS([
{
comment: 'ccc',
who: 'c1',
buttonInfo: ['a', 'b'],
},
{
comment: 'ddd',
who: 'd2',
buttonInfo: ['a''],
},
]);
This is working:
a.concat(b)
But this is not working:
[...a ,...b]
// or
b.map(v => {
a.push(v);
})

you can use concat method as it said in doc:
const list1 = List([ 1, 2, 3 ]);
const list2 = List([ 4, 5, 6 ]);
const array = [ 7, 8, 9 ];
const list3 = list1.concat(list2, array);
// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

An ImmutableJS list has a method named concat whose behavior is the same as a normal javascript array. However, you cannot use spread syntax for an Immutable array.
Also the syntax for push is different from the normal array, push like concat with Immutable List returns a new list, your map method will look like
b.map(v => {
a = a.push(v);
})
P.S. Using the above method though will mutate your array a. You must create a new List and then push both the array contents into it if you want to use push. However concat is the best way for your case

For add List to List in Immutable.js, you can use merge method.
Example:
const a = fromJS(
[
{
comment: 'aaaa',
who: 'a1',
buttonInfo: ['a', 'b', 'c'],
},
{
comment: 'bb',
who: 'a2',
buttonInfo: ['a', 'b', 'c'],
},
]
);
const b = fromJS(
[
{
comment: 'ccc',
who: 'c1',
buttonInfo: ['a', 'b'],
},
{
comment: 'ddd',
who: 'd2',
buttonInfo: ['a''],
},
]
);
a.merge(b);

Related

Filtering an array with an array of values

I have 2 arrays and i'd like to filter one array with the other. E.g. if array1 includes any of the values in array2, they should be returned.
The two arrays are:
const array1 = [a, b, c, d]
The other array, which should be filtered where 'id' is equal to any of the values in array1 is:
const array2 = [
{
id: b
title: title1
},
{
id: d
title: title2
},
{
id: f
title: title3
}
]
The easiest way is to use two for-loops. Possible not the fastest approach.
res = [];
for (var i = 0;i<array1.length;i++) {
for (var j = 0;j<array2.length;j++) {
if (array1[i] == array2[j].id) {
res.push(array2[j]);
break;
}
}
}
You could use Array.prototype.filter() and Array.prototype.indexOf():
const array1 = ['a', 'b', 'c', 'd'];
const array2 = [{
id: 'b',
title: 'title1'
}, {
id: 'd',
title: 'title2'
}, {
id: 'f',
title: 'title3'
}];
const result = array2.filter(function(x){
return array1.indexOf(x.id) !== -1;
});
Adding this missing '', You can use filter and includes methods of Array.
const array1 = ['a', 'b', 'c', 'd'];
const array2 = [
{
id: 'b',
title: 'title1'
},
{
id: 'd',
title: 'title2'
},
{
id: 'f',
title: 'title3'
}
]
const result = array2.filter(({id}) => array1.includes(id));
console.log(result);

Efficiently sort a disordered "subset" array based on the order of an already sorted "master" array

I have two arrays of IDs. One is an unfiltered master array that has been sorted based on values in a separate dataset object, whose keys are are the aforementioned IDs). The other array is a filtered subset of master, which is sorted in the same way as master. Like so:
const dataset = {a: {...}, b: {...}, c: {...}, d: {...}, e: {...}, f: {...}, g: {...}}
const master = ['a', 'b', 'c', 'd', 'e']
const filtered = ['a', 'c', 'd']
However, sometimes, the sort criteria changes, so I re-sort the master array. I could then re-filter this newly sorted master array in order to get my filtered array, but what I would rather do is just sort the filtered array based on the new order of the master array, as I assume this would be more efficient than running my filters again.
However, I'm not sure how to do it. For clarity, I think I want a flow something like this:
const mySort = (unsortedSubset, blueprint) => {
// do sort here
}
const dataset = {a: {...}, b: {...}, c: {...}, d: {...}, e: {...}, f:
const master = ['e', 'd', 'c', 'b', 'a']
const filtered = ['a', 'c', 'd']
const sortedFiltered = mySort(filtered, master)
console.log(sortedFiltered)
// ['d', 'c', 'a']
You could filter the master array by using the filtered array for lookup.
const
mySort = (subset, blueprint) => blueprint.filter(v => subset.includes(v));
dataset = { e: {}, d: {}, c: {}, b: {}, a: {} },
master = ['e', 'd', 'c', 'b', 'a'],
filtered = ['a', 'c', 'd'],
sortedFiltered = mySort(filtered, master);
console.log(sortedFiltered);
A version with a Set
const
mySort = (subset, blueprint) => blueprint.filter(Set.prototype.has, new Set(subset));
dataset = { e: {}, d: {}, c: {}, b: {}, a: {} },
master = ['e', 'd', 'c', 'b', 'a'],
filtered = ['a', 'c', 'd'],
sortedFiltered = mySort(filtered, master);
console.log(sortedFiltered);

How to find a value in object of objects with an array of keys

for example I have an object that that has objects and arrays in itself:
const object =
{
a: {
b: [
0: 'something',
1: {
c: 'the thing that I need',
},
],
},
};
and an array that has the keys as values:
const array =
[
'a', 'b', '1', 'c',
];
How can I use this array to navigate in the object and give me the value?
Maybe there is a way to do this with ramda? or just in general to make it look human readable.
You can reduce the array defining the path through the object.
You do have an error in the array. The path should be: [ 'a', 'b', '1', 'c' ], because the thing you need is inside the second element of the b array, not the first.
const object = {
a: {
b: [
'something',
{ c: 'the thing that I need' }
],
},
};
const path = [ 'a', 'b', '1', 'c' ];
const result = path.reduce(( source, next ) => source[ next ], object );
console.log( result );
Ian Hoffman-Hicks' superb crocks library has a function that does exactly that
import propPathOr from 'crocks/helpers/propPathOr'
const getC = propPathOr(null, ['a', 'b', '0', 'c'])
getC({ a: { b: [{ c: 'gotcha!' }] } }) === 'gotcha!' // true
This function is called path in Ramda.

Add a property to array of object based on the existence of value in another array

I have an array to check with main array as,
const arrayToCheck = ['a', 'b', 'c', 'd'];
Here is the Main array,
const mainArray = [ {name:'alex', code: 'c'},
{name:'jack', code: 'd'},
{name:'john', code: 'n'},
{name:'mike', code: 'l'}
]
I want to add a status property with key of either 'enable' or 'disable' to the mainArray based on the values in arrayToCheck.
So the output should be
[ {name:'alex', code: 'c', status: 'enable'},
{name:'jack', code: 'd', status: 'enable'},
{name:'john', code: 'n', status: 'disable'},
{name:'mike', code: 'l', status: 'disable'}
]
I have tried map and some to get the desired output but that did not work out,
Here is what i have tried,
const output = this.mainArray.map( (fil, i) => {
return arrayToCheck.some( s => {
if (s === fil.Code) {
this.mainArray[i].Status = 'enable'
} else {
this.mainArray[i].Status = 'disable'
}
})
});
You could use map method with includes and spread syntax .... This solution returns new array of objects and doesn't modify original array.
const arrayToCheck = ['a', 'b', 'c', 'd'];
const mainArray = [ {name:'alex', code: 'c'}, {name:'jack', code: 'd'}, {name:'john', code: 'n'}, {name:'mike', code: 'l'}]
const result = mainArray.map(e => ({...e, status: arrayToCheck.includes(e.code) ? "enable" : "disable"}))
console.log(result)
A couple of things there:
JavaScript is case-sensitive. Code and code are not the same property.
You're not returning anything from your map callback, so map isn't the right tool. If you just want to loop through, use a loop or forEach.
Use the return value of some, rather than doing the if within its callback. But, here you don't need some, because you can use includes.
Assuming you want to do what you did in your question (modify the existing objects, rather than creating new ones):
const arrayToCheck = ['a', 'b', 'c', 'd'];
const mainArray = [ {name:'alex', code: 'c'}, {name:'jack', code: 'd'}, {name:'john', code: 'n'}, {name:'mike', code: 'l'}];
mainArray.forEach(entry => {
entry.status = arrayToCheck.includes(entry.code) ? "enable" : "disable";
});
console.log(mainArray);
If you wanted to create new objects, Nenad's answer shows you how to do that. But I didn't get that from your question.
Here is easy to understand code:
const arrayToCheck = ['a', 'b', 'c', 'd'];
const mainArray = [ {name:'alex', code: 'c'}, {name:'jack', code: 'd'}, {name:'john', code: 'n'}, {name:'mike', code: 'l'}]
const output = mainArray.map(obj => {
obj.status = arrayToCheck.indexOf(obj.code) < 0 ? 'disable' : 'enable';
return obj;
})
console.log(output);

Ramda: Extract flat array of uniq values

I do have a working code like the following, but I am wondering if there is a way with Ramda to turn this whole expression into a curried function where I can specify the input data argument. Perhaps even compose a whole thing differently.
const data = [
{ val: ['A', 'B'] },
{ val: ['C', 'D'] },
{ val: ['A', 'C', 'E'] },
]
R.uniq(R.flatten(R.map(R.prop('val'), data)))
I tried using R.__, but that's probably working differently, not for such nested calls.
Here's a simple transformation of your function, using compose:
const {compose, uniq, flatten, map, prop} = R;
const data = [
{ val: ['A', 'B'] },
{ val: ['C', 'D'] },
{ val: ['A', 'C', 'E'] },
]
const extract = compose(uniq, flatten, map(prop('val')))
console.log(extract(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
This could also be written with Ramda's order-reversed twin of compose, pipe:
const {pipe, uniq, flatten, map, prop} = R;
const data = [
{ val: ['A', 'B'] },
{ val: ['C', 'D'] },
{ val: ['A', 'C', 'E'] },
]
const extract = pipe(
map(prop('val')),
flatten,
uniq
)
console.log(extract(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
I personally choose compose for one-liners, pipe for anything longer.
The notion of function composition expressed in these two functions is quite central to Ramda. (Disclaimer: I'm a Ramda author.)

Categories

Resources