how to put a regex test inside a arr.find - javascript

I have an array like so:
const arr = [{id: "12f"},{id: "12F"},{id: "13"}]
const itemToBeFound = {id: "12f"}
I want to be able to find that item using something like RegExp(/12f/i).test(string)
So the point of using the regexp is to be case insensitive. I know I could use toLowerCase or toUpperCase, I was just wanting to know how to do it this way.
So arr.find(({id}) => id == regexp) something to that affect. I haven't been able to figure out how to achieve this yet.

You need to just test the property against the RegExp
const arr = [{
id: "12f"
}, {
id: "12F"
}, {
id: "13"
}];
var regexp = new RegExp(/12f/i);
console.log(arr.find(({id}) => /12f/i.test(id)))
console.log(arr.filter(({id}) => /12f/i.test(id)))

This one-liner does all the job, according to the current question setup:
const foundItems = arr.filter((item) => (/[itemToBeFound.id]/gi).test(item.id))

The pattern and flags params of RegExp can be leveraged conduct dynamic comparison like so:
// Loose Match.
const filter = (array, target) => {
const regex = new RegExp(target.id, 'i')
return array.filter(x => regex.test(x.id))
}
// Proof.
console.log('12f', filter([{id: "12f"},{id: "12F"},{id: "13"}], {id: "12f"}))
console.log('13', filter([{id: "12f"},{id: "12F"},{id: "13"}], {id: "13"}))

Related

how can i check if an array of objects contains a key which is in array of strings js?

We have an array of objects like
const arr = [{id: "someId", name: {...}}, ...];
const skippedKeys = ["id"...]
How can i filtered the array of object based on skipped keys?
The result should be:
const result = [{name: {...}}, ...];
Also i don't want to make a cycle inside the cycle.
the result also could be implemented using lodash library.
we should remove key with value as well.
Since you stated that it could be implemented using lodash, here is some code using lodash:
let result = _.map(arr, (el)=> _.omit(el, skippedKeys))
const result = arr.map(obj =>
Object.keys(obj).reduce(
(res, key) => (
skippedKeys.includes(key) ? res : {...res, [key]: obj[key]}
),
{},
));
It's simple and no need for any nested cycles. There are two option to do that
Using includes function
const result = arr.filter((item) => !result.includes(item.id));
Using set
const dataSet = new Set(skippedKeys);
const result = arr.filter((item) => !dataSet.has(item.id));
I prefer the second one as it excludes double checks. Hope the answer was helpful.

How can I extract an array of substring via regex in nodes?

I have a string var whose value is (1,2)(3,4) and I'd like to extract an array [[1,2],[3,4]] from it. The solution I have is to use str.match but I haven't figured out how to extract the array.
I have tried:
> '(1,2)(3,4)'.match(/([\d]+),([\d])*/)
[ '3,2', '3', '2', index: 1, input: '(3,2)(4,5)', groups: undefined ]
The result is not what I want. So what should I do with the regex for that?
You need to use /(\d+),(\d+)/g or - to only get those inside parentheses - /\((\d+),(\d+)\)/g and get the results using RegExp#exec in a loop:
var s = '(1,2)(3,4)', m, results=[];
var rx = /(\d+),(\d+)/g;
while(m=rx.exec(s)) {
results.push([m[1], m[2]])
}
console.log(results);
Or, with matchAll if you target the latest JS environments:
const s = '(1,2)(3,4)', rx = /(\d+),(\d+)/g;
const results = [...s.matchAll(rx)];
console.log(Array.from(results, x => [x[1],x[2]]))
There's the other way around, without using RegExp, just in case:
const src = '(1,2)(3,4)',
result = src
.slice(1,-1)
.split(')(')
.map(s => s.split(','))
console.log(result)
.as-console-wrapper{min-height:100%;}

Parsing a templated string

I have a string like this
const str = 'map("a")to("b");map("foo")to("bar");map("alpha")to("beta");'
I wanted to parse this string to generate a json something like
[{id: 'a', map: 'b'},
{id: 'foo', map: 'bar'},
{id: 'alpha', map: 'beta'}]
I was wondering if regex is the best way to do this or if theres any utility lib I could leverage
Here's a regex that should work for your current case:
const str = 'map("a")to("b");map("foo")to("bar");map("alpha")to("beta");';
const res = str.split(";").map(e => {
const k = e.match(/map\("(.+?)"\)to\("(.+?)"\)/);
return k && k.length === 3 ? {id: k[1], map: k[2]} : null;
}).filter(e => e);
console.log(res);
The idea is to split on semicolons (a lookaround could be used to handle cases when semicolons are part of your desired key/value), then map these pairs into the desired object format based on a regex that parses the map("")to("") format. Finally, nulls are filtered out.
I'm pretty sure there is a nice regex solution which is shorter and faster, but since i'm bad at regex i solve those things like that:
const str = 'map("a")to("b");map("foo")to("bar");map("alpha")to("beta");'
const result = str.split(';').map(e => {
const parts = e.substring(3).split('to').map(item => item.replace(/\W/g, ''));
return {
id: parts[0],
map: parts[1]
};
})
console.log(result);

Remove elements from array using spread

I have an array of animals arr = ['cat','dog','elephant','lion','tiger','mouse']
I want to write a function remove(['dog','lion']) which can remove the elements from arr, can we write this function using es6 spread?
example:
arr = ['cat','dog','elephant','lion','tiger','mouse']
remove(['cat', 'lion'])
arr should get changed to
arr = ['dog','elephant','tiger','mouse']
Note: I don't want mutations, so please don't suggest solutions that mutates array.
No, you can't, because they're not next to each other. There's been some discussion of taking spread and rest syntax further, but even in those discussions, I don't think a series of discontiguous selections would be possible.
I think the closest you can get is to call out the first few specifically and then use rest syntax for everything after 'lion':
const arr = ['cat','dog','elephant','lion','tiger','mouse'];
const arr2 = [arr[1], arr[2], ...arr.slice(4)];
console.log(arr2);
...which I'm sure isn't what you wanted to do. :-)
From what I understand you're looking for a function that has its argument defined using the spread syntax.
Here is an example:
var arr = ['cat','dog','elephant','lion','tiger','mouse'];
function remove(...toRemove){
toRemove.forEach(item => {
var index = arr.indexOf(item);
if(index != -1){
arr.splice(index, 1);
}
})
}
remove('dog', 'lion'); // OR remove(...['dog', 'lion']);
console.log(arr);
This is actually changing the original array (it mutates it) you've mentioned that you're not looking for mutation but you've also mentioned this arr should get changed to...
I don't understand the selected answer was selected since it does not contain solution to the end goal of removing elements from an array
You can't use spread alone to remove, but you can slice and spread:
function removeOne(sourceList, value) {
const index = sourceList.indexOf(value);
if (index >= 0 && index < sourceList.length) {
return [
...sourceList.slice(0, index),
...sourceList.slice(index+1),
];
}
return sourceList;
}
function remove(sourceList, removeList) {
let res = [...sourceList]
removeList.forEach((item) => {
res = removeOne(res, item);
})
return res;
}
you can use the array.filter method, it will return array with filtered values,
var filterMe = ["cat", "dog", "elephant", "lion", "tiger", "mouse"];
var answer = filterMe.filter((item) => item !== "dog")
.filter((item) => item !== "lion");
console.log(answer);
You can use spread if you want to pass lots of strings like remove('lion', 'dog'). Otherwise I don't think spread can help you.
You could take an iterator and exclude the values from iteration with spread operator.
Btw, it is not really advisable.
function remove(array, items) {
array[Symbol.iterator] = function* () {
for (let value of Object.values(this)) {
if (!items.includes(value)) {
yield value;
}
}
};
}
var array = ['cat', 'dog', 'elephant', 'lion', 'tiger', 'mouse'];
remove(array, ['dog', 'lion']);
console.log([...array]);
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Similar to the previous filter solution, but using a regular expression. Beneficial if the remove array is large...
let arr = ['cat', 'dog', 'elephant', 'lion', 'tiger', 'mouse'];
const removeArr = ['cat', 'lion'];
const removeRegExp = new RegExp(removeArr.join('|'));
arr = arr.filter(e => !removeRegExp.test(e));
console.log(arr);
If you're using Typescript, you can also use the Omit utility type to remove specific keys from you object/ array.
Assuming an interface like this
interface Todo {
title: string;
description: string; // <--- assuming you want to omit `description` key
completed: boolean;
createdAt: number;
}
type TodoPreview = Omit<Todo, "description">;
the TodoPreview type will now expect an object with the other members included but with decription omitted
This will now be correct
const todo: TodoPreview = {
title: "Clean room",
completed: false,
createdAt: 1615544252770,
};
This will ERROR out
const todo: TodoPreview = {
title: "Clean room",
completed: false,
description: 'this should not be here' // <--- TS compiler will complain
createdAt: 1615544252770,
};

A better approach instead of using String replace in javascript

I am trying to do some operations for each element of an array of strings, when it matches a regexp.
I have been able to resolve this by using the replace function:
const anyRegExp = new RegExp('string[(\d)]');
const sampleArr = ['string[1].name','string[2].name' /*,...*/]
const myOp1 = (...args) => /* operations */
const myOp2 = (...args) => /* different operations */
sampleArr.forEach(key => key.replace(anyRegExp, (par1, par2, par3, par4) => {
console.log(par1, par2, par3, par4);
// prints: 'string[1]', '1', 1, 'string[1].name'
// 'string[2]', '2', 2, 'string[2].name'
if (par3 > 1) {
myOp(par1,par2,par3,par4);
} else {
myOp2(par1,par2,par3,par4);
}
}));
As you see, I am not really needing the replace operation at all. I know it does not modify my key anyway, I'd just love to know if there is any other kind of function defined in String more appropiate for this job.
I tried match, but it does not receive a function as second parameter.
Output Sample (With google chrome)
const temp1 = /Tests.MyTests\[(\d+)\]/
const temp2 = "Tests.MyTests[0].name"
temp2.match(temp1, (...args) => console.log('args',args))
outputs--> ["Tests.MyTests[0]", "0"]
temp2.replace(temp1, (...args) => console.log('args',args))
logs--> args ["Tests.MyTests[0]", "0", 0, "Tests.MyTests[0].name"]
outputs--> "undefined.name"
As it can be seen, replace, receives a function, which gives me 4 parameters, which are the ones I want to use.
match does not log anything
const temp1 = /Tests.MyTests\[(\d+)\]/
const temp2 = "Tests.MyTests[0].name"
temp2.match(temp1, (...args) => console.log('args',args));
const temp1 = /Tests.MyTests\[(\d+)\]/
const temp2 = "Tests.MyTests[0].name"
temp2.replace(temp1, (...args) => console.log('args',args))
You might be looking for
for (let key of sampleArr)
myOp(...key.match(anyRegExp)) // or anyRegExp.exec(key)
assuming that the regex always matches the whole string, not multiple times on parts of it
you can use split then join for example you want to replace any symbol characters regex with "-" then
myString.split(/[^\w-]/).join('-')

Categories