I am trying to drip feed array data, so it acts like it's coming in one at the time with RxJS.
What i want to achieve is i have a promise that gives an array like this:
['a', 'b', 'c']
Then i want to emit one value at the time like this:
['a']
['a', 'b']
['a', 'b', 'c']
So i can use it in a backtest. I did it like this, but i don't know if it can be done in a cleaner way?
const createDripDataObservable = OHLCData => (
Observable.range(1, OHLCData.length)
.map(t => OHLCData.slice(0, t))
)
export const dripObservable = (promise, ObservableFunc = Observable.fromPromise) =>
ObservableFunc(promise)
.flatMap(data => createDripDataObservable(data.data.result[TIME_FRAME]))
The reason for adding observableFunc is because apparently marble test in RxJS 5 doesn't accept promises. This is the most clean way i could think of. But maybe there is another way? I would like to just add a promise, so the test is more realistic.
describe('Historic market data', () => {
it('should drip historic data so it acts like real time', () => {
const testScheduler = new TestScheduler((a, b) => expect(a).toEqual(b))
// setup
const lhsMarble = 'x'
const expected = '(abc)'
const lhsInput = { x: { data: { result: { [TIME_FRAME]: ['a', 'b', 'c'] } } } }
const expectedMap = {
a: ['a'],
b: ['a', 'b'],
c: ['a', 'b', 'c'],
}
const lhs$ = testScheduler.createHotObservable(lhsMarble, lhsInput)
const actual$ = dripObservable(lhs$, Observable.from)
testScheduler.expectObservable(actual$).toBe(expected, expectedMap)
testScheduler.flush()
})
})
I'm pretty satisifed with the test, except that i can't add a promise so i have to do Observable.from
I'm fairly new to RxJS and reactive streams so i would like some feedback on this!
Related
I'm trying to convert an array of arrays into an array of nested objects in JavaScript. Let's assume each subarray in the array represents a file path. I want to create an array of objects where each object has 2 properties, the name of the current file and any files/children that come after the current file/parent.
So for example, if I have this array of arrays where each subarray represents a file path:
[['A', 'B', 'C'], ['A', 'B', 'D'], ['L', 'M', 'N']]
I want to get this as the result:
[
{
name :'A',
children: [
{
name: 'B',
children: [
{
name: 'C',
children: []
},
{
name: 'D',
children: []
}
]
}
]
},
{
name: 'L',
children: [
{
name: 'M',
children: [
{
name: 'N',
children: []
}
]
}
]
}
]
I tried mapping through the array of arrays and creating an object for the current file/parent if it hasn't been created yet. I think I may be on the right track but I can't seem to think of the best way to do so.
Something I could do in 5 minutes, it probably can be improved. This could also be written as a recursive function, I believe.
const result = [];
arr.forEach((subArr) => {
var ref = result;
subArr.forEach((name) => {
const obj = ref.find((obj) => obj.name == name);
if (obj) {
ref = obj.children;
} else {
ref.push({ name, children: [] });
ref = ref[ref.length - 1].children;
}
});
});
Here's mine:
// Function to convert path array ‘a’ from position ‘i’ into tree structure in ‘v’.
const tree = (a, i, v) => {
if (i < a.length) { tree(a, i+1, v[a[i]] ||= { }) }
}
// Function to convert a simple node into the desired record format.
const record = (v) => {
const a = [];
for (const [k, w] of Object.entries(v)) {
a.push({ name: k, children: record(w) });
}
return a;
}
const m = { }
for (const a of [['A', 'B', 'C'], ['A', 'B', 'D'], ['L', 'M', 'N']]) {
tree(a, 0, m);
}
const result = record(m);
While it might be overkill for this requirement, I have handy a variant of one of my utility functions, setPath, that is used for adding such a path to an existing array. This is a bit different from the other answers in that it does this in an immutable way, returning a new object that shares as much structure as possible with the original one. I always prefer to work with immutable data.
Using that, we can write a hydrate function to do this job as the one-liner, const hydrate = (paths) => paths .reduce (setPath, []).
This is quite likely overkill here, as there is probably no reason to build your output one immutable level after another. But it is a demonstration of the value of keeping utility functions handy.
The code looks like this:
const call = (fn, ...args) => fn (...args)
const setPath = (xs, [name, ...names]) => call (
(i = ((xs .findIndex (x => x .name == name) + 1) || xs .length + 1) - 1) =>
name == undefined
? [...xs]
: [
...xs .slice (0, i),
{name, children: setPath ((i == xs .length) ? [] : xs [i] .children, names)},
...xs .slice (i + 1)
]
)
const hydrate = (paths) => paths .reduce (setPath, [])
console .log (
hydrate ([['A', 'B', 'C'], ['A', 'B', 'D'], ['L', 'M', 'N']])
)
.as-console-wrapper {max-height: 100% !important; top: 0}
We have a trivial call helper function that I use here to avoid statements. As much as possible, I prefer to work with expressions, as these avoid temporal notions in code brought on by statements, and they compose much better into larger pieces. We could alternatively do this with default parameters, but they have other problems. A trivial call function handles this nicely.
In our main function, we destructure apart the first name in the input from the remaining ones. Then we pass to call a function that calculates the index of the element with our existing name in the input array. If it doesn't exist, the index will be the length of that array. This is perhaps over-tricky. findIndex returns -1 if no element matches. We add 1 to the result, and then, if it's 0, we choose one more than the length of the array. Finally we subtract 1 from the result, and now the index will be where we found our target or the length of the array if it wasn't found.
Now, if the path is empty, we return a copy of our array. (I prefer the copy just for consistency, but it would be legitimate to just return it directly.) If it's not empty, we use the index to tear apart our input array, keeping everything before it, building a new item for that index by recursively calling setPath with the remaining node names, and then keeping everything after that index.
And now, as noted, our hydrate function is a trivial fold of setPath starting with an empty array.
I have many values in string array. ['A','B','C','D','E'].
I have to search like this. if Array contains A ,B then it is admin. if it contains C,E then it is resercher. if it is containing B,C,D then it is manager.
I am writing below code for it. its not working. can you please help me on same.
const groups = ['A','B','C','D','E']
for (let i = 0; i < groups.length; i++) {
if (groups[i]==='A'&& groups[i] ==='B' ) setAdmin(true);
if (groups[i]==='C' && groups[i] ==='E' ) setResearcher(true);
if (groups[i]==='B' && groups[i] ==='C' && groups[i] ==='D' ) setRiskMgr(true);
}
I know it is not working because it is comparing element with multiple values. How can I resolve this?
You can use every and includes to utilize your logic
const groups = ['A', 'B', 'C', 'D', 'E']
const userGroups = {
admin: ['A', 'B'],
researcher: ['C', 'E'],
riskManager: ['B', 'C', 'D']
}
function setAdmin() {
console.log('admin')
}
function setResearcher() {
console.log('researcher')
}
function setRiskMgr() {
console.log('risk manager')
}
if (userGroups.admin.every(group => groups.includes(group))) setAdmin(true);
if (userGroups.researcher.every(group => groups.includes(group))) setResearcher(true);
if (userGroups.riskManager.every(group => groups.includes(group))) setRiskMgr(true);
Less repeated code with a separate object for role checks
const groups = ['A', 'B', 'C', 'D', 'E']
const userGroups = {
admin: {
values: ['A', 'B'],
set: function() {
setAdmin(true)
}
},
researcher: {
values: ['C', 'E'],
set: function() {
setResearcher(true)
}
},
riskManager: {
values: ['B', 'C', 'D'],
set: function() {
setRiskMgr(true);
}
}
}
function setAdmin() {
console.log('admin')
}
function setResearcher() {
console.log('researcher')
}
function setRiskMgr() {
console.log('risk manager')
}
for(const key in userGroups) {
if(userGroups[key].values.every(group => groups.includes(group))) {
userGroups[key].set();
}
}
As #ChrisG mentioned, you can use Array.includes or Array.some instead.
const groups = ['A','B','C','D','E']
if (groups.some(group => ['A', 'B'].includes(group))) {
setAdmin(true);
} else if (...) {
...
}
Its quite a simple solution with Array.includes
const groups = ['A','B','C','D','E']
if(groups.includes('A') && groups.includes('B')) {
setAdmin(true);
} else if(groups.includes('C') && groups.includes('E')) {
setReasercher(true)
} // ...
Assuming there is no issue with React useState, are you referring to OR, || statement, if so #Nick Vu has the answer, since you are just looping through the groups list, there is NO WAY to have two same element at single integration.
Else, if you want to achieve AND, && condition, then solution is otherwise.
const groups = ['A','B','C','D','E']
function setAdmin() {
console.log('admin')
}
function setResearcher() {
console.log('researcher')
}
function setRiskMgr() {
console.log('risk manager')
}
if(arr.some(a=>a==="A")&&arr.some(a=>a==="B")) setAdmin(true);
if(arr.some(a=>a==="C")&&arr.some(a=>a==="E")) setResearcher(true);
if(arr.some(a=>a==="B")&&arr.some(a=>a==="C")&&arr.some(a=>a==="D")) setRiskMgr(true);
Is there a way to generate a nested JavaScript Object from entries?
Object.fromEntries() doesn't quite do it since it doesn't do nested objects.
const entries = [['a.b', 'c'], ['a.d', 'e']]
// Object.fromEntries(entries) returns:
{
'a.b': 'c',
'a.d': 'e',
}
// whatIAmLookingFor(entries) returns:
{
a: {
b: 'c',
d: 'e',
}
}
You could reduce the array entries and reduce the keys as well. Then assign the value to the final object with the last key.
const
setValue = (object, [key, value]) => {
const
keys = key.split('.'),
last = keys.pop();
keys.reduce((o, k) => o[k] ??= {}, object)[last] = value;
return object;
},
entries = [['a.b', 'c'], ['a.d', 'e']],
result = entries.reduce(setValue, {});
console.log(result);
I think I found a way using lodash:
import set from 'lodash/set'
const result = {}
const entries = [['a.b', 'c'], ['a.d', 'e']]
entries.forEach((entry) => {
const key = entry[0]
const value = entry[1]
set(result, key, value)
})
I've just started exploring Ramda library and fall into some problem.
Let's say we have a function, that takes string and list of strings as arguments and returns true if given string is in the list. At line 4 I want to log first element from otherList that is not included in list.
const isInList = R.curry((name: string, list: string[]) => list.some(elem => elem === name))
const list = ['a', 'b', 'c']
const otherList = ['a', 'b', 'd', 'c']
console.log(otherList.find(!isInList(R.__, list)))
I can't find Ramda function that would reverse logical result of given function.
If it existed it would look like something like this:
const not = (func: (...args: any) => boolean) => (...args: any) => !func(args)
Then my goal could be archived like:
console.log(otherList.find(not(isInList(R.__, list)))
Does function like that exsist in Ramda?
R.complement is the way to negate a function
const isInList = R.includes;
const isNotInList = R.complement(isInList);
const list = ['Giuseppe', 'Francesco', 'Mario'];
console.log('does Giuseppe Exist?', isInList('Giuseppe', list));
console.log('does Giuseppe Not Exist?', isNotInList('Giuseppe', list));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js" integrity="sha256-xB25ljGZ7K2VXnq087unEnoVhvTosWWtqXB4tAtZmHU=" crossorigin="anonymous"></script>
Found it! It's called R.complement()
Try R.difference():
const list = ['a', 'b', 'c']
const otherList = ['a', 'b', 'd', 'c']
R.difference(otherList, list); //=> ['d']
Online demo here
I would like to get a value from an object with accessing it with array of strings.
Static example: Input: ['a','b','c'] Output: function (t) { t.a.b.c; }
I would like to make a function that resolves the problem for any array.
function (state) {
let value = state;
for (let i = 0; i < propNames.length; i++) {
value = value[propNames[i]];
}
return value;
};
Other solution is a generator for a function by reducer.
These are working. I would like to know if there is any other faster solutions that I didn't think of.
You can test here the algorithms. There is a place where your code can be added.
A fast way to do it is to iterate over the properties and access the inner objects sequentially, you can do this using Array.reduce() or a for loop:
const get = (obj, props) => props.reduce((out, p) => out && out[p] || undefined, obj);
const obj = { a: { b: { c: 5 } } };
console.log(get(obj, ['a', 'b', 'c']));
console.log(get(obj, ['a', 'b', 'c', 'd', 'e']));
Or, you could evaluate the expression using eval(), however, this is probably the slowest way to do it, I do not recomment it:
const get = (obj, props) => {
try {
return eval(`obj.${props.join('.')}`);
} catch {
return undefined;
}
}
const obj = { a: { b: { c: 5 } } };
console.log(get(obj, ['a', 'b', 'c']));
console.log(get(obj, ['a', 'b', 'c', 'd', 'e']));