searching multiple values in string array in javascript/react - javascript

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);

Related

How to push data in empty space in array using foreach loop?

I have this below code where in I am trying to push 'No Data' in one of the index in array which doesn't have data.
data = ['a', 'b', '', 'd', 'e'];
onClick() {
this.data.forEach(element => {
if (element == '') {
element.push('No Data');
}
});
console.log(this.data);
}
But I am getting error as TypeError: element.push is not a function.
What is wrong in the code and is there any better ways to solve this?
let list = this.data.map(d => d === '' ? 'No data' : d)
Each element of your array is a string.
Strings don't have a push method and they cannot because they are immutable. That is you can't change the characters in a string.
This is trivially solved however, as follows:
this.data = this.data.map(d => d === '' ? 'No Data' : d);
What we've done here, is use Array.prototype.map to transform the array into a new array with all of the empty string elements replaced as per your specifications.
In context:
data = ['a', 'b', '', 'd', 'e'];
onClick() {
this.data = this.data.map(d => d === '' ? 'No Data' : d);
console.log(this.data);
}
element is the string you can't push, use array.map to solve this
const data = ['a', 'b', '', 'd', 'e'];
onClick() {
const list = this.data.map(element => {
if (element === '') {
return 'No Data';
}
return element;
});
console.log(list);
}
You could map the array with replacements.
let data = ['a', 'b', '', 'd', 'e'];
data = data.map(v => v || 'No Data');
console.log(data);
data = ['a', 'b', '', 'd', 'e'];
var dataArray = new Array();
data.forEach(element => {
if (element == '') {
dataArray.push('No Data');
}
else
{
dataArray.push(element);
}
});
console.log(this.dataArray);
Because element is a string while push function is only supported for array. Just return 'No data' in case element is empty string:
data = ['a', 'b', '', 'd', 'e'];
onClick() {
this.data = this.data.map(v => v || 'No Data');
console.log(this.data);
}
When you use for or for each loop so that particular element is a string, not an array that why its shows element.push is not a function.
to change element of an array you can use this method
data = ['a', 'b', '', 'd', 'e'];
for (var i = 0; i < data.length; i++){
if (data[i] == '')
data[i] = 'No Data';}
console.log(data)

Get equals values from two nested objects

Suppose I have two objects like these ones:
const obj1 = {
ch1: {
as: ['a', 'b'],
ns: ['1']
}
ch2: {
ss: ['#', '*', '+'],
ts: ['2', '3']
}
}
const obj2 = {
ch1: {
as: ['a', 'g'],
}
ch2: {
ss: ['#', '-', '+'],
ts: ['1', '5']
}
}
const result = findSimilarities(obj1, obj2)
should returns:
[
'a' // because obj1.ch1.as and obj2.ch1.as contain 'a'
'#' // because obj1.ch2.ss and obj2.ch2.ss contain '#'
'+' // because obj1.ch2.ss and obj2.ch2.ss contain '+'
]
I can define Level 1 as ch1 or ch2, Level 2 as as, ns, ss or ts and Level 3 the strings inside the arrays.
So what I'm interested in are che value at level 3 that the two objects have in common.
Honestly I didn't know how to start..
What I would do is start with a function, function getMatches(obj1, obj2) { ....
Iterate over the first-level keys of obj1 with Object.keys(obj1).foreach( key2 => .... (2 to represent what you call level 2)
Then, iterate over THOSE keys, Object.keys(obj1[key2]).foreach(key3 > ...
So now you have an array that you can access via obj1[key2][key3], and you can access the array to compare against via obj2[key2][key3]. So now you just have to iterate every value in obj1[key2][key3] and check if it's in obj2[key2][key3]. If a key is in both, smash it in an array, and then return the array at the end of the function
[edit] you may have to use some sort of check, or the optional chaining operator ?., to access the keys on obj2, in case there's a key on obj1 that isn't on obj2
Here is what I would recommend:
Create a function lets call it function compare(obj1, obj2), then create two Object.values variables followed by an empty array var equivalent = [];
After that have a forEach function that searches both objects, and the final product should look something like:
function compare(obj1, obj2) {
var values1 = Object.values(obj1);
var values2 = Object.values(obj2);
var equivalent = [];
var keys = Object.keys(obj1);
keys.forEach(k => {
if (obj1.hasOwnProperty(k) && obj2.hasOwnProperty(k)) {
if (obj1[k] === obj2[k]) {
equivalent.push(obj1[k]);
}
}
});
console.log(equivalent);
}
compare(obj1, obj2);
I also want to leave my solution here. It will work properly on the data structures like you described above. On whatever object depth and if arrays will contains only primitive values.
function findSimilarities(obj1, obj2) {
if (obj1 instanceof Array && obj2 instanceof Array) {
return findSimilarArrayValues(obj1, obj2)
}
if (!obj1 instanceof Object || !obj1 instanceof Object) {
return [];
}
const similarKeys = findSimilarObjectKeys(obj1, obj2);
return similarKeys.map(key => findSimilarities(obj1[key], obj2[key])).flat()
}
function findSimilarObjectKeys(obj1, obj2) {
return Object.keys(obj1).filter(key => obj2.hasOwnProperty(key));
}
function findSimilarArrayValues(arr1, arr2) {
return arr1.filter(item => arr2.includes(item));
}
Try to start with Object.keys, Object.entries and Object.values.
Good luck!
Use Object.keys to find all keys in first object, Object.protoype.hasOwnProperty() to check if these keys exist in object 2
Repeat that for levels 1 and 2
Extract the values common to level 3 arrays using Array.prototype.filter() on the array from first object to keep only items found in its match from second object:
function findSimilarities(x, y) {
const res = [];
for (const k1 of Object.keys(x)) { //Level 1
if (y.hasOwnProperty(k1)) {
const xo1 = x[k1];
const yo1 = y[k1];
for (const k2 of Object.keys(xo1)) { //Level 2
if (yo1.hasOwnProperty(k2)) {
const xo2 = xo1[k2];
const yo2 = yo1[k2];
if (Array.isArray(xo2) && Array.isArray(yo2)) { //Level 3 are arrays
const dupXo2 = xo2.filter(el => yo2.includes(el));
res.push(...dupXo2);
}
}
}
}
}
return res;
}
const obj1 = {
ch1: {
as: ['a', 'b'],
ns: ['1']
},
ch2: {
ss: ['#', '*', '+'],
ts: ['2', '3']
}
};
const obj2 = {
ch1: {
as: ['a', 'g'],
},
ch2: {
ss: ['#', '-', '+'],
ts: ['1', '5']
}
};
const result = findSimilarities(obj1, obj2);
console.log(result);

JavaScript: from an array of objects of an array of objects, extract value of a property as array

I have a JavaScript object array with the following structure:
somedata = {
foo: {
bar: [
{
baz: [
{
someprop: 'a'
},
{
someprop: 'b'
},
{
someprop: 'c'
}
]
},
{
baz: [
{
someprop: 'd'
},
{
someprop: 'e'
},
{
someprop: 'f'
}
]
}
]
}
}
I want to extract someprop field from this JavaScript object as an array ['a', 'b', 'c', 'd', 'e', 'f']
currently, this is my code logic to extract someprop field as an array:
const result = []
somedata.foo.bar.forEach(x => {
x.baz.forEach(y => {
result.push(y.someprop)
})
})
console.log(result) // prints ["a", "b", "c", "d", "e", "f"]
i tried to make the code more reusable by creating a function:
function extractToArray(data, arr, prop) {
let result = []
data.forEach(x => {
x[arr].forEach(y => {
result.push(y[prop])
})
})
return result;
}
console.log(extractToArray(somedata.foo.bar, 'baz', 'someprop'))
But is there a more concise, elegant, cleaner way to achieve this?
Note: possible duplicate covers an array of objects, but this is regarding an array of objects of an array of objects (so a simple map solution won't work).
You can use flatMap for that:
const somedata = {foo:{bar:[{baz:[{someprop:"a"},{someprop:"b"},{someprop:"c"}]},{baz:[{someprop:"d"},{someprop:"e"},{someprop:"f"}]}]}};
const result = somedata.foo.bar.flatMap(({baz}) => baz.map(({someprop}) => someprop));
console.log(result);
Note that not every current browser supports this yet, so you might want to use a polyfill.
You could create recursive function that will find your prop on any level and return array as a result.
const somedata = {"foo":{"bar":[{"baz":[{"someprop":"a"},{"someprop":"b"},{"someprop":"c"}]},{"baz":[{"someprop":"d"},{"someprop":"e"},{"someprop":"f"}]}]}}
function get(data, prop) {
const result = [];
for (let i in data) {
if (i == prop) result.push(data[prop]);
if (typeof data[i] == 'object') result.push(...get(data[i], prop))
}
return result;
}
console.log(get(somedata, 'someprop'))
A recursive function that does it in one functional expression:
const extractToArray = (data, prop) => Object(data) !== data ? []
: Object.values(data).flatMap(v => extractToArray(v, prop))
.concat(prop in data ? data[prop] : []);
var somedata = {foo: {bar: [{baz: [{someprop: 'a'},{someprop: 'b'},{someprop: 'c'}]},{baz: [{someprop: 'd'},{someprop: 'e'},{someprop: 'f'}]}]}}
console.log(extractToArray(somedata, "someprop"));
This is reusable in the sense that it also works when the property is not always present, or not always at the same depth within the data structure.
For others with similar question, I am adding a more generic (but possibly a bit less efficient) alternative using the JSON.parse reviver parameter
var arr = [], obj = {foo:{bar:[{baz:[{someprop:"a"},{someprop:"b"},{someprop:"c"}]},{baz:[{someprop:"d"},{someprop:"e"},{someprop:"f"}]}]}}
JSON.parse(JSON.stringify(obj), (k, v) => k === 'someprop' && arr.push(v))
console.log(arr)

Take array of strings as property accessor

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']));

Drip feed array data with RxJS

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!

Categories