I'm embarrassed to post this but I could really use a hand here. This code just looks nasty. I have a feeling that I can write a cleaner approach with filter or reduce but can't seem to stab it. Any thoughts, community?
const vin = detections.map(detection => {
return detection.textAnnotations.map(v => {
let n = v.description.replace(/\s+/g, '');
if (n.length === 17) {
return n;
}
});
})[0][0];
Thanks!
Just an attempt to refactor your code:
const getMatchedTextAnnotation = (textAnnotation) => {
const n = textAnnotation.description.replace(/\s+/g, '');
return n.length === 17 ? n : null;
}
const extractAnnotationsFromDetection = (detection) => {
return detection.textAnnotations.reduce((arr, textAnnotation) => {
const n = getMatchedTextAnnotation(textAnnotation);
return !!n ? [ ...arr, n] : arr;
}, [])
}
const vinArr = detections.reduce((arr, detection) => {
const subArr = extractAnnotationsFromDetection(detection);
return !!subArr ? [ ...arr, ...subArr ] : arr;
}, [])
const vin = !!vinArr ? vinArr[0] : null;
Related
I am currently working on an array of functions and want to get the right function back with a condition.
Here is my code :
{'key':'a', 'function':func_a},
{'key':'b', 'function':func_b},
{'key':'c', 'function':func_c},
{'key':'d', 'function':func_d}
];
const term = 'b';
const funcToDo = for (var i = 0; i < array.length; i++) {
if (term === a[i].key) {
return a[i].function
}
}
const shouldIDoIt = true;
shouldIDoIt === true ? functToDo() : null;
Can someone help me on this ?
Use Array.prototype.find to then return from that array an Object which matches a specific property value
const find = (arr, k, v) => arr.find(ob => ob[k] === v);
const func_a = () => console.log("aaa!");
const func_b = () => console.log("bbb!");
const func_c = () => console.log("ccc!");
const arrFn = [
{key: "a", function: func_a},
{key: "b", function: func_b},
{key: "c", function: func_c},
];
const funcToDo = find(arrFn, "key", "b")?.function;
const shouldIDoIt = true;
funcToDo && shouldIDoIt && funcToDo();
Example, I have a path(prefix) like this: A/B/C/
I want to get bellow list:
[{name:"A",path:"A/"},
{name:"B",path:"A/B/",
{name:"C",path:"A/B/C/"
]
I can split the path to a array, then loop the array to build the new list of object.
But in my mind, I just know there should be a simple and smarter way to achieve this by using reducer, but just stuck here.
You're right that you could use a reducer. Something like this:
const str = "A/B/C/"
const arr = str.split("/").filter(Boolean).reduce((acc, name) => {
const path = [...acc.map(o => o.name), name].join("/") + "/"
return [...acc, { name, path }]
}, [])
console.log(arr)
You can solve this with map, but maybe not as cleanly as you were anticipating:
const result = 'A/B/C'
.split('/')
.filter(x => x)
.map((name, i, arr) => {
const prev = arr[i - 1];
return prev
? { name, path: `${prev.name}${name}/` }
: { name, path: `${name}/` };
});
My odd solution, but I think sdgluck's is the cleanest answer.
arr = "A/B/C/"
.split("/")
.filter(e => e)
.map((e, i, a) => {
a2 = a.filter((el, ix) => {
if (ix <= i) return el;
});
return {[e] : a2.join("/")};
});
Beginner at JavaScript here. Below is a JS challenge I've just completed for a course. The challenge:
Clean the room function: given an input of [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20], make a function that organizes these into individual array that is ordered. For example answer(ArrayFromAbove) should return: [[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591]
My solution:
let originalArray = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
const compareFunction = ((a, b) => {
return a-b;
});
let counter = 1;
const groupFunction = (currentValue, index, arr) => {
nextNumber = arr[index + 1];
if (currentValue === nextNumber){
counter++;
} else {
if (counter > 1){
let filledArray = new Array(counter).fill(currentValue);
counter = 1;
return filledArray;
} else {
return currentValue;
}
}
};
const filterFunction = (currentValue) => {
return currentValue !== undefined;
}
const finalFunction = (arr) => {
arr.sort(compareFunction);
let groupedArray = arr.map(groupFunction);
let finalArray = groupedArray.filter(filterFunction);
return finalArray;
}
finalFunction (originalArray);
Everything returns correctly, however I am under the impression that it is bad practice to declare global variables. With my "counter" variable, if I assign it within the groupFunction, the counter resets every loop through the array, making it useless. Where would be the appropriate place to put this variable? Is there another method / approach that would be better suited for the problem all together? Thank you!
In my opinion, your code is very hard to read, and it would probably be better if you'd rewrite it somehow, but I will leave that up to you. One thing you can do, to remove this global variable, is to use a concept called higher order function.
const higherOrderFunction = () => {
let counter = 1;
const groupFunction = (currentValue, index, arr) => {
nextNumber = arr[index + 1];
if (currentValue === nextNumber){
counter++;
} else {
if (counter > 1){
let filledArray = new Array(counter).fill(currentValue);
counter = 1;
return filledArray;
} else {
return currentValue;
}
}
}
return groupFunction;
};
You then get access to your groupFunction by calling the higher order function,
but the variable does not pollute your global scope:
let groupFunction = higherOrderFunction()
Here's a much shorter approach, that I know as beginner will have you searching to learn what some of the stuff used does, if you did not learn about it already.
Stay Curious.
const finalFunction = (arr) => {
const map = arr.reduce((acc, curr) => {
acc[curr] = (acc[curr] || 0) + 1;
return acc;
}, {});
return Object.keys(map)
.sort((a, b) => a - b)
.reduce((acc, val) => {
const value = Number(val);
acc.push(map[val] > 1 ? Array(map[val]).fill(value) : value);
return acc;
}, []);
};
And another one:
const finalFunction = (arr) => arr.sort((a, b) => a - b)
.reduce((acc, curr) => {
const last = acc.pop();
return curr === last
? [...acc, [curr, curr]]
: last && curr === last[0]
? [...acc, [...last, curr]]
: [...acc, ...(last ? [last] : []), curr];
}, []);
This question already has answers here:
Why can't we have return in the ternary operator?
(6 answers)
Closed 2 years ago.
stepping through with a breakpoint at second for...in with if (map[t[i]]), expected false but actual is true. can someone help explain why this occurs?
const s = 'rat',
t = 'car';
const isAnagram = (s, t) => {
if (s.length !== t.length) {
return false;
}
const map = {};
for (let i in s) {
map[s[i]] ? map[s[i]]++ : (map[s[i]] = 1);
}
for (let i in t) {
// this works
// if (map[t[i]]) {
// map[t[i]]--;
// } else {
// return false;
// }
// this doesn't ?¿?¿
map[t[i]] ? map[t[i]]-- : false;
}
return true;
};
console.log(isAnagram(s, t)); // false
const isAnagram = (s, t) => {
const [sMap, tMap] = [s, t].map(
str =>
str.toLowerCase().replace(/\s/g, "").split("").reduce((map, cursor) => {
map[cursor] = 1 + (map[cursor] ? map[cursor] : 0);
return map;
}, {})
);
return !Object.keys(sMap).some(prop => sMap[prop] !== tMap[prop]);
}
console.log(isAnagram("me", "hobo")); // false
// all true
console.log(isAnagram("rail safety", "fairy tales"));
console.log(isAnagram("debit card", "bad credit"));
console.log(isAnagram("William Shakespeare", "I am a weakish speller"));
You could just sort strings, filter whitespaces and compare:
const s = 'rat';
const t = 'tar'
const u = "cat";
isAnagram = (s, t) =>
[...s].filter(c => c !== ' ').sort().join() === [...t].filter(c => c !== ' ').sort().join()
console.log(isAnagram(s, t))
console.log(isAnagram(s, u))
I have a list of work history objects that have start and end date fields. I need to sort by start and then by end. If the dates overlap between work history objects when I use back-to-back sort() functions, the order can potentially be off. I need a way to sort an ImmutableJS List by multiple keys where the second sort key is only processed when first key values are equal. I would have assumed that ImmutableJS would have a simpler way to handle this type of sorting. Here is what I came up with, but this feels horrible to me (using momentJS for date comparison):
const sortedWorkHistory = workHistory.sort((b, a) => {
const aTo = moment(a.get('to') === null ? undefined : a.get('to'));
const bTo = moment(b.get('to') === null ? undefined : b.get('to'));
if (aTo.isBefore(bTo)) {
return -1;
}
if (bTo.isBefore(aTo)) {
return 1;
}
return 0;
})
.sort((b, a) => {
const aTo = moment(a.get('to') === null ? undefined : a.get('to'));
const bTo = moment(b.get('to') === null ? undefined : b.get('to'));
if (aTo === bTo) {
const aFrom = moment(a.get('from'));
const bFrom = moment(b.get('from'));
if (aFrom.isBefore(bFrom)) {
return -1;
}
if (bFrom.isBefore(aFrom)) {
return 1;
}
return 0;
}
});
You could put that into a single compare function like this:
const sortedWorkHistory = workHistory.sort((b, a) => {
const aTo = moment(a.get('to'));
const bTo = moment(b.get('to'));
const aFrom = moment(a.get('from'));
const bFrom = moment(b.get('from'));
if (aTo.isBefore(bTo)) {
return -1;
} else if (bTo.isBefore(aTo)) {
return 1;
} else if (aFrom.isBefore(bFrom)) {
return -1;
} else if (bFrom.isBefore(aFrom)) {
return 1;
}
return 0;
});
Or maybe even
const sortedWorkHistory = workHistory.sort((b, a) => {
// aTo = ...
if (aTo.isSame(bTo)) {
return aFrom.diff(bFrom);
}
return aTo.diff(bTo);
});
aTo === bTo is never going to be equal the way you are defining it. You're comparing references to objects which are always different. You'll need to use moments .isSame method. You can verify that by trying this:
const a = moment().startOf('day');
const b = moment().startOf('day');
console.log(a === b); // false
console.log(a.isSame(b)); // true
Here is what I'd do:
// Helper function to create moments
function parseMoment(date) {
return moment(date === null ? undefined : date);
}
const sortedWorkHistory = workHistory
.sort((a, b) => parseMoment(a.get('to')).diff(parseMoment(b.get('to'))))
.sort((a, b) => {
if(parseMoment(a.get('to')).isSame(parseMoment(b.get('to')))) {
return parseMoment(a.get('from')).diff(parseMoment(b.get('from')))
}
return 0;
});