How to do a recursively method in javascript - javascript

I'm trying to create a recursive method to find.
But I don't understand why it finds the element but returns undefined.
How can solve it, please?
Here is my code:
export const findDmaFromHierarchy = (hierarchy: [], value: string): any => {
let founded = undefined;
hierarchy.forEach((dma: any) => {
if (dma.children) {
findDmaFromHierarchy(dma.children, value);
}
if (String(dma.value) === String(value)) {
console.log("founded: ", dma);
founded = Object.assign({}, dma);
return founded;
}
});
return founded;
};

You don't set founded when the recursive call finds the value.
export const findDmaFromHierarchy = (hierarchy: [], value: string): any => {
let founded = undefined;
hierarchy.forEach((dma: any) => {
if (dma.children) {
founded = findDmaFromHierarchy(dma.children, value);
if (founded) {
return founded;
}
}
if (String(dma.value) === String(value)) {
console.log("founded: ", dma);
founded = Object.assign({}, dma);
return founded;
}
});
return founded;
};

You could take Array#some and return early on found.
Then I suggest to check if the value is found and assign the object and return with true. To move this check in front of the function omits unnecessary checks for children objects.
For children take a temporary variable and check it and assign and return if truthy.
export const findDmaFromHierarchy = (hierarchy: [], value: string): any => {
let found = undefined;
hierarchy.some((dma: any) => {
if (String(dma.value) === String(value)) {
console.log("founded: ", dma);
found = Object.assign({}, dma);
return true;
}
if (dma.children) {
let temp = findDmaFromHierarchy(dma.children, value);
if (temp) {
found = temp;
return tru;
}
}
});
return found;
};

Related

Extract the assignment of from this expression with sonarQube

when I launch a sonar control I find myself with a smells code for the following function:
const changeMedia = (value: any, step: any) => {
step.definition?.steps
.filter((obj: any) => obj.media.includes(value))
.map((item: any) => {
if (value === 'EMAIL') {
return (item.media = 'LETTER');
} else if (value === 'LETTER') {
return (item.media = 'EMAIL');
}
return item;
});
};
I get the following sonar alert:
Extract the assignment of "item.media" from this expression.
What would be the solution to avoid this sonar message?
const changeMedia = (value, step) => {
step.definition?.steps
.filter((obj) => obj.media.includes(value))
.map((item) => {
if (value === 'EMAIL') {
item.media = 'LETTER'
return item; // returning item instead of (item.media = 'LETTER')
} else if (value === 'LETTER') {
item.media = 'EMAIL'
return item;
}
return item;
});
};

Angular ngrx: assign a readonly property

I'm building an Angular App with Ngrx and I'm encountering a problem. Here it is:
In the OnInit, i launch dispatch and selector for getting my datas from store and i want to edit these datas.
I get an error 'Cannot assign to read only property 'title' of object '[object Object]'' when i try to do that: x.title = ${x.title} (${count})
I understand why i can't reassign, state is immutable. Yes but, how can i edit my datas? I started by do that in the effect but it's display logic, i think i've to do that in a component logic.
There's my OnInit function:
ngOnInit() {
this.store.dispatch(new GetAllProducts());
this.store.select(selectResourcesList).pipe(
distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
)
.pipe(tap((res => {
res.resources.map(x => {
let count = 0;
res.events.map(y => {
if (y.resourceId === x.id) {
count += y.extendedProps.quantity;
return count;
}
return count;
});
x.title = `${x.title} (${count})`;
});
})))
.subscribe((res) => {
this.resources = res.resources;
this.events = res.events;
this.cdr.detectChanges();
});
}
edit:
I had try to edit my data in the subscribe like this, but get the same error:
ngOnInit() {
this.store.dispatch(new GetAllProducts());
this.store.select(selectResourcesList).pipe(
distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)))
.subscribe((res) => {
const tempResources = [...res.resources];
const tempEvents = [...res.events];
tempResources.map(x => {
let count = 0;
tempEvents.map(y => {
if (y.resourceId === x.id) {
count += y.extendedProps.quantity;
}
});
x.title = `${x.title} (${count})`;
});
this.resources = tempResources;
this.events = tempEvents;
this.cdr.detectChanges();
});
}
Thanks in advance for your help ;-)
I found a solution for bypass store immutability:
I had to create a copy of result of selector (with spread operator) and do the changes on it.
Like this:
ngOnInit() {
this.store.dispatch(new GetAllProducts());
this.store.select(selectResourcesList).pipe(
distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)))
.subscribe((res) => {
let tempResources = [...res.resources];
let tempEvents = [...res.events];
tempResources = tempResources.map(x => {
let count = 0;
tempEvents = tempEvents.map(y => {
if (y.resourceId === x.id) {
count += y.extendedProps.quantity;
}
return y;
});
x = {
...x,
title: `${x.title} (${count})`
};
return x;
});
this.resources = tempResources;
this.events = tempEvents;
this.cdr.detectChanges();
});
}

Angular & Firebase get data in observable in value changes

Problem with got data correctly execute function many one times, these function is execute in ngOnInit one time with abstraction but i dont know ocurrs these problem in a server, i thing in snapshotChanges but i don't know.
thx for help
https://i.stack.imgur.com/EinQg.png
return <Observable<Products[]>> t.db.collection(PATHS_FIRESTORE.products).snapshotChanges()
.pipe(
map(actions => {
let arr = actions.map((res) => {
let doc: any = <any>res.payload.doc.data()
let obj: any = {}
if (!isNullOrUndefined(cart)) {
for (const prod in cart) {
if (cart.hasOwnProperty(prod)) {
const element = cart[prod];
if (doc.uid === prod) {
obj[doc.uid] = {
name_product: doc.name_product,
path_img: doc.path_img,
price: doc.price,
quantity: doc.quantity + element.total,
uid: doc.uid,
uid_local: doc.uid_local
}
} else {
t.db.collection(PATHS_FIRESTORE.products).doc(prod).ref.get().then( res => {
const data = res.data()
return obj[res.id] = {
name_product: data.name_product,
path_img: data.path_img,
price: data.price,
quantity: element.total,
uid: doc.uid,
uid_local: doc.uid_local
}
})
}
}
console.log(obj)
}
return obj
}else {
obj = {
...doc
}
return obj
}
})
.filter((b: any) => {
return b.uid_local === uid_local
})
.filter((b: any) => {
return b.quantity > 0
})
.filter((b: any) => {
return !b.status
})
console.log(arr)
return arr
})
)

javascript array filter very slow in REACT

I have a custom listbox, a div that contains a vertical list of other div children. And I have input for search something else in the list. It's working but in large data, it's working very slowly.
Also search criterion produce dynamically with column chooser. How can i increase search performance.
Firsly, prepare filter data for search and keeping state on the page load
prepareFilterData(allData) {
const filteredData = [];
let columnChooser = JSON.parse(getItemFromLocalStorage("ColumnData"));
allData.map(item => {
var data = "";
columnChooser.map(element => {
var newData = { value: item[element.value], format: element.format };
var filterItem = getFilterDataFormat(newData);
data += filterItem + " ";
});
filteredData.push(data);
});
this.setState({
filteredData: filteredData
});
}
Secondly, When user enter an char to textbox, i'm checking filteredData
filterList() {
const updatedList = this.state.allData.length > 0 ? this.state.allData : [];
var filteredData = [];
filteredData = updatedList.filter((item, index) => {
const data = this.state.filteredData[index];
return data.indexOf(this.state.searchInputValue) !== -1;
});
return filteredData;
}
This is input statement
<input
id="searchBox"
type="text"
className="filter-input empty"
placeholder="Search"
onChange={this.filterList}
value={this.props.state.searchInputValue}
style={{ width: "100%" }} />
Using a standard for loop can significantly increase the performance, especially in your case where you're using indexOf which is causing another iteration in your filter. The filter operation uses callbacks and it's often used because of the simpler syntax but it's these callback that make the operation to be slower especially on big data.
Read more here.
I found the solution.
SOLUTION:
I create a util.js in my project, and I called createFilter function.
import Fuse from "fuse.js";
import { toTrLowerCase } from "./process";
function flatten(array) {
return array.reduce((flat, toFlatten) => flat.concat(Array.isArray(toFlatten) ? flatten(toFlatten) : toFlatten), []);
}
export function getValuesForKey(key, item) {
const keys = key.split(".");
let results = [item];
keys.forEach(_key => {
const tmp = [];
results.forEach(result => {
if (result) {
if (result instanceof Array) {
const index = parseInt(_key, 10);
if (!isNaN(index)) {
return tmp.push(result[index]);
}
result.forEach(res => {
tmp.push(res[_key]);
});
} else if (result && typeof result.get === "function") {
tmp.push(result.get(_key));
} else {
tmp.push(result[_key]);
}
}
});
results = tmp;
});
// Support arrays and Immutable lists.
results = results.map(r => (r && r.push && r.toArray ? r.toArray() : r));
results = flatten(results);
return results.filter(r => typeof r === "string" || typeof r === "number");
}
export function searchStrings(strings, term, { caseSensitive, fuzzy, sortResults, exactMatch } = {}) {
strings = strings.map(e => e.toString());
try {
if (fuzzy) {
if (typeof strings.toJS === "function") {
strings = strings.toJS();
}
const fuse = new Fuse(
strings.map(s => {
return { id: s };
}),
{ keys: ["id"], id: "id", caseSensitive, shouldSort: sortResults }
);
return fuse.search(term).length;
}
return strings.some(value => {
try {
if (!caseSensitive) {
value = value.toLowerCase();
}
if (exactMatch) {
term = new RegExp("^" + term + "$", "i");
}
if (value && value.search(term) !== -1) {
return true;
}
return false;
} catch (e) {
return false;
}
});
} catch (e) {
return false;
}
}
export function createFilter(term, keys, options = { caseSensitive: false, fuzzy: false, sortResults: false, exactMatch: false }) {
debugger;
return item => {
if (term === "") {
return true;
}
if (!options.caseSensitive) {
term = term.toLowerCase();
}
const terms = term.split(" ");
if (!keys) {
return terms.every(term => searchStrings([item], term, options));
}
if (typeof keys === "string") {
keys = [keys];
}
return terms.every(term => {
// allow search in specific fields with the syntax `field:search`
let currentKeys;
if (term.indexOf(":") !== -1) {
const searchedField = term.split(":")[0];
term = term.split(":")[1];
currentKeys = keys.filter(key => key.toLowerCase().indexOf(searchedField) > -1);
} else {
currentKeys = keys;
}
return currentKeys.some(key => {
const values = getValuesForKey(key, item);
values[0] = toTrLowerCase(values[0]);
return searchStrings(values, term, options);
});
});
};
}
And then i added fuse.js to package.json.
"fuse.js": "^3.0.0"
I called createFilter function like that... term is searching value key
keysToFilter is which array column you wanna search.
this.state.allData.filter(createFilter(term, this.state.keysToFilter));
Link: https://github.com/enkidevs/react-search-input

How to log the program flow of a very deep and complex functional JavaScript code?

I'm trying to understand the flow of the functions in this reselect library. I currently use console.log to log the output. Still, it is hard to understand the flow. Make me think how complex functional programming is!!!
How can I intercept the calls and log the function name and the parameters to the console with ES6 decorator or Proxy or any other language features?
function defaultEqualityCheck(a, b) {
return a === b
}
function areArgumentsShallowlyEqual(equalityCheck, prev, next) {
if (prev === null || next === null || prev.length !== next.length) {
return false
}
// Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.
const length = prev.length
for (let i = 0; i < length; i++) {
if (!equalityCheck(prev[i], next[i])) {
return false
}
}
return true
}
function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
let lastArgs = null
let lastResult = null
console.log("Entering defaultMemoize");
console.log("###INPUT### defaultMemoize argument func type: " + typeof func);
// we reference arguments instead of spreading them for performance reasons
return function () {
if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
// apply arguments instead of spreading for performance.
lastResult = func.apply(null, arguments)
}
lastArgs = arguments
return lastResult
}
}
function getDependencies(funcs) {
const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs
if (!dependencies.every(dep => typeof dep === 'function')) {
const dependencyTypes = dependencies.map(
dep => typeof dep
).join(', ')
throw new Error(
'Selector creators expect all input-selectors to be functions, ' +
`instead received the following types: [${dependencyTypes}]`
)
}
return dependencies
}
function createSelectorCreator(memoize, ...memoizeOptions) {
console.log("Entering createSelectorCreator");
console.log("#INPUT# argument memoize name: " + memoize.name);
console.log("#INPUT# argument memoize options: ");
console.log(memoizeOptions);
return (...funcs) => {
let recomputations = 0
const resultFunc = funcs.pop()
const dependencies = getDependencies(funcs)
console.log("##INPUT## argument funcs: ");
console.log(resultFunc);
const memoizedResultFunc = memoize(
function () {
recomputations++
// apply arguments instead of spreading for performance.
return resultFunc.apply(null, arguments)
},
...memoizeOptions
)
console.log("memoizedResultFunc: " + typeof memoizedResultFunc);
// If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
const selector = defaultMemoize(function () {
const params = []
const length = dependencies.length
if (arguments != null)
{
console.log("***INPUT*** arguments: ");
console.log(arguments);
}
for (let i = 0; i < length; i++) {
// apply arguments instead of spreading and mutate a local list of params for performance.
params.push(dependencies[i].apply(null, arguments))
}
// apply arguments instead of spreading for performance.
return memoizedResultFunc.apply(null, params)
})
selector.resultFunc = resultFunc
selector.recomputations = () => recomputations
selector.resetRecomputations = () => recomputations = 0
return selector
}
}
const createSelector = createSelectorCreator(defaultMemoize)
function createStructuredSelector(selectors, selectorCreator = createSelector) {
if (typeof selectors !== 'object') {
throw new Error(
'createStructuredSelector expects first argument to be an object ' +
`where each property is a selector, instead received a ${typeof selectors}`
)
}
const objectKeys = Object.keys(selectors)
return selectorCreator(
objectKeys.map(key => selectors[key]),
(...values) => {
return values.reduce((composition, value, index) => {
composition[objectKeys[index]] = value
return composition
}, {})
}
)
}
const shopItemsSelector = state => state.shop.items
const taxPercentSelector = state => state.shop.taxPercent
const subtotalSelector = createSelector(
shopItemsSelector,
items => items.reduce((acc, item) => acc + item.value, 0)
)
const taxSelector = createSelector(
subtotalSelector,
taxPercentSelector,
(subtotal, taxPercent) => subtotal * (taxPercent / 100)
)
const totalSelector = createSelector(
subtotalSelector,
taxSelector,
(subtotal, tax) => ({ total: subtotal + tax })
)
let exampleState = {
shop: {
taxPercent: 8,
items: [
{ name: 'apple', value: 1.20 },
{ name: 'orange', value: 0.95 },
]
}
}
console.log(subtotalSelector(exampleState))// 2.15
//console.log(taxSelector(exampleState))// 0.172
//console.log(totalSelector(exampleState))// { total: 2.322 }

Categories