How to append elements in an array to another array? - immutability

How to append elements in an array to another array using Ramdajs with a single line statement?
state = {
items:[10,11,]
};
newItems = [1,2,3,4];
state = {
...state,
taggable_friends: R.append(action.payload, state.taggable_friends)
};
//now state is [10,11,[1,2,3,4]], but I want [10,11,1,2,3,4]

Ramda's append works by "pushing" the 1st param into a clone of the 2nd param, which should be an array:
R.append('tests', ['write', 'more']); //=> ['write', 'more', 'tests']
R.append(['tests'], ['write', 'more']); //=> ['write', 'more', ['tests']]
In your case:
R.append([1,2,3,4], [10,11]); // => [10,11,[1,2,3,4]]
Instead use RamdaJS's concat, and reverse the order of the parameters:
R.concat(state.taggable_friends, action.payload)

If you want to use just basic JavaScript you can do this:
return {
...state,
taggable_friends: [...state.taggable_friends, action.payload],
}

Related

Laravel - Assert json array ids using wildcard

In my application I have a response like this:
{
"items": [
{
"id": 10,
"field": "foo"
},
{
"id": 20,
"field": "bar"
}
]
}
I need to test the content of items and validate each id.
I've tried many solutions but no one works, for example (this is just a kind of pseudo-code):
assertJson(fn (AssertableJson $json) =>
$json->where('items.*.id', [10, 20])
)
Is there a way to use a wildcard to pick every ID and validate using an array?
You can use array_filter:
$idArray = [10, 20];
$myObj = json_decode($json); // Turn JSON to obj
$items = $myObj["items"]; // Get items from object
// Filter the items for items that aren't in the ID list
$invalidItems = array_filter($items, function ($el) {
// If the item has an id which isn't in the array, return true
return !in_array($el["id"], $idArray);
});
// This returns true if we found 0 items with IDs not in the ID list
return $invalidItems == [];
You can similarly use array_map to simplify your array, then compare it to your ID array:
$myObj = json_decode($json); // Turn JSON to obj
$items = $myObj["items"]; // Get items from object
$outIdArray = array_map(function($el) {
return $el["id"];
}, $items);
// Compare $outIdArray to [10, 20]
Not tested yet but below should work.
We attach an each on each child element under items and add a callback to where on that id key of each child.
<?php
assertJson(fn (AssertableJson $json) =>
$json->each('items', fn (AssertableJson $childJson) =>
$childJson->where('id', fn($idVal) =>
in_array($idVal, [10,20])
)
)
)

Filter an Array in an Observable

Here is an edited sample from learnrxjs. I want to filter the values in the type array. But thats not how it works: 'This condition will always return 'true' since the types 'string[]' and 'string' have no overlap.'
I am new to rxjs and cant figure out how to filter the array. Any advices? Is it possible?
const source = from([
{ name: 'Joe', age: 31, type: ['a', 'b'] },
{ name: 'Bob', age: 25, type: ['a'] }
]);
//filter out people with type b
const example = source.pipe(filter(person => person.type != 'a'));
//output: "People with type b: Bob"
const subscribe = example.subscribe(val => console.log(`Type a: ${val.name}`));
the filter() you are applying takes a function with signature T => boolean meaning that you will have to return a boolean true/false so it can filter out elements from the stream.
Your elements T are of type Object {name:string, age:number, type:array} so to filter on values in the type Array you will need to use the Array.indexOf prototype function:
source.pipe(filter(person => person.type.indexOf('b') == -1) // filter out people who have type b

How can the evaluation of a ngrx-store selector be controlled?

I have a selector:
const mySelector = createSelector(
selectorA,
selectorB,
(a, b) => ({
field1: a.field1,
field2: b.field2
})
)
I know the selector is evaluated when any of its inputs change.
In my use case, I need to control "mySelector" by a third selector "controlSelector", in the way that:
if "controlSelector" is false, "mySelector" does not evaluate a new value even in the case "selectorA" and/or "selectorB" changes, and returns the memoized value
if "controlSelector" is true, "mySelector" behaves normally.
Any suggestions?
Selectors are pure functions..its will recalculate when the input arguments are changed.
For your case its better to have another state/object to store the previous iteration values.
You can pass that as selector and based on controlSelector value you can decide what you can return.
state : {
previousObj: {
...
}
}
const prevSelector = createSelector(
...,
(state) => state.previousObj
)
const controlSelector = createSelector(...);
const mySelector = createSelector(
controlSelector,
prevSelector,
selectorA,
selectorB,
(control, a, b) => {
if(control) {
return prevSelector.previousObj
} else {
return {
field1: a.field1,
field2: b.field2
};
}
}
)
Sorry for the delay...
I have finally solved the issue not using NGRX selectors to build up those "higher selectors" and creating a class with functions that use combineLatest, filter, map and starWith
getPendingTasks(): Observable<PendingTask[]> {
return combineLatest(
this.localStore$.select(fromUISelectors.getEnabled),
this.localStore$.select(fromUISelectors.getShowSchoolHeadMasterView),
this.memStore$.select(fromPendingTaskSelectors.getAll)).pipe(
filter(([enabled, shmView, tasks]) => enabled),
map(([enabled, shmView, tasks]) => {
console.log('getPendingTasks');
return tasks.filter(task => task.onlyForSchoolHeadMaster === shmView);
}),
startWith([])
);
}
Keeping the NGRX selectors simple and doing the heavy lifting (nothing of that in this example, though) in this kind of "selectors":
- will generate an initial default value (startWith)
- will not generate new value while filter condition fails (that is, when not enabled, any changes in the other observables do not fire a new value of this observable)

Perform sequential api calls with RxJs?

Is there a way in RxJs to perform two api calls where the second requires data from the first and return a combined result as a stream? What I'm trying to do is call the facebook API to get a list of groups and the cover image in various sizes. Facebook returns something like this:
// call to facebook /1234 to get the group 1234, cover object has an
// image in it, but only one size
{ id: '1234', cover: { id: '9999' } }
// call to facebook /9999 to get the image 9999 with an array
// with multiple sizes, omitted for simplicity
{ images: [ <image1>, <image2>, ... ] }
// desired result:
{ id: '1234', images: [ <image1>, <image2>, ... ] }
So I have this:
var result = undefined;
rxGroup = fbService.observe('/1234');
rxGroup.subscribe(group => {
rxImage = fbService.observe(`/${group.cover.id}`);
rxImage.subscribe(images => {
group.images = y;
result = group;
}
}
I want to create a method that accepts a group id and returns an Observable that will have the combined group + images (result here) in the stream. I know I can create my own observable and call the next() function in there where I set 'result' above, but I'm thinking there has to be an rx-way to do this. select/map lets me transform, but I don't know how to shoe-in the results from another call. when/and/then seems promising, but also doesn't look like it supports something like that. I could map and return an observable, but the caller would then have to do two subscribes.
Looks like flatMap is the way to go (fiddle). It is called like subscribe and gives you a value from a stream. You return an observable from that and it outputs the values from all the created observables (one for for each element in the base stream) into the resulting stream.
var sourceGroup = { // result of calling api /1234
id: '1234',
cover: {
id: '9999'
}
};
var sourceCover = { // result of calling api /9999
id: '9999',
images: [{
src: 'image1x80.png'
}, {
src: 'image1x320.png'
}]
};
var rxGroup = Rx.Observable.just(sourceGroup);
var rxCombined = rxGroup.flatMap(group =>
Rx.Observable.just(sourceCover)
.map(images => ({
id: group.id,
images: images.images
}))
)
rxCombined.subscribe(x =>
console.log(JSON.stringify(x, null, 2)));
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.all.min.js"></script>
Result:
{
"id": "1234",
"images": [
{
"src": "image1x80.png"
},
{
"src": "image1x320.png"
}
]
}
You should use concatMap instead of flatMap, it will preserve the order of the source emissions.

How do I removed a particular item from a embedded array in RethinkDB?

given sample data like:
{
'id': 1,
'things': [{'name': 'a'},{'name': 'b'},{'name': 'c'}]
}
how do I update the document removing the array item with name of 'b' from the embedded array?
r.table('test')
.get(1)
.update({things: r.row('things')????});
You can use the update command along with filter to filter the elements in an array and pass to along to update.
r.table('30848200').get(1).update(function (row) {
return {
'things': row('things')
.filter(function (item) { return item('name').ne('b') })
}
})
Basically, you'll be overwriting things with the filtered array.

Resources