Related
I have an array like this .
{
"filters": [
{
"filterProperty": "companyType",
"filterValues": [
"Private"
]
},
{
"filterProperty": "city",
"filterValues": [
"Mumbai",
"SanJose",
"Shanghai"
]
}
]
}
I have applied Filters. now I am removing them One by One and calling an API with remaining Filters.
so when I pass filterProperty as "city" and value as "Mumbai" then only "Mumbai" would remove from filterProperty "city" . the rest filter values should be same.
How can I do so ?
"filters": [
{
"filterProperty": "companyType",
"filterValues": [
"Private"
]
},
{
"filterProperty": "city",
"filterValues": [
"Mumbai",
"SanJose",
"Shanghai"
]
}
]
let data = filters.splice(a=> a.filterProperty === 'city' && a.filterValues.filter(a => a == "Mumbai"))
I assume you need map along with filter. Something like this:
const obj = { "filters": [ { "filterProperty": "companyType", "filterValues": [ "Private" ] }, { "filterProperty": "city", "filterValues": [ "Mumbai", "SanJose", "Shanghai" ] } ]};
const result = obj.filters.map(k=>(k.filterProperty == "city" ? (k.filterValues = k.filterValues.filter(o=>o!=='Mumbai'), k) : k ));
console.log(result);
Use Array.reduce()
let filters=[{filterProperty:"companyType",filterValues:["Private"]},{filterProperty:"city",filterValues:["Mumbai","SanJose","Shanghai"]}];
let data = filters.reduce((acc,cur) => {
if(cur.filterProperty === "city"){
cur.filterValues.splice(cur.filterValues.indexOf("Mumbai"),1)
}
acc.push(cur)
return acc
},[])
console.log(data)
Without mutating the data, use forEach and filter build new array of items.
const filter = (obj, prop, value) => {
const filters = [];
obj.filters.forEach(({ filterProperty, filterValues }) => {
filters.push({
filterProperty,
filterValues: filterValues.filter((item) =>
filterProperty === prop ? item != value : true
),
});
});
return {
filters,
};
};
const data = {
filters: [
{
filterProperty: "companyType",
filterValues: ["Private"],
},
{
filterProperty: "city",
filterValues: ["Mumbai", "SanJose", "Shanghai"],
},
],
};
const prop = "city";
const value = "Mumbai";
console.log(filter(data, prop, value));
Solution with mutating the data, using find and splice
const data = {
filters: [
{
filterProperty: "companyType",
filterValues: ["Private"],
},
{
filterProperty: "city",
filterValues: ["Mumbai", "SanJose", "Shanghai"],
},
],
};
const prop = "city";
const value = "Mumbai";
const city = data.filters.find(({ filterProperty }) => filterProperty === prop);
if (city) {
const index = city.filterValues.findIndex((item) => item === value);
if (index > -1) {
city.filterValues.splice(index, 1);
}
}
console.log(data);
Array;
arr=[
{
id: [ '5e6e9b0668fcbc7bce2097ac', '5e6e9b0e68fcbc7bce2097af' ],
color: [ 'a', 'b' ]
}
]
Models;
const varyant = Models.varyant
function;
Promise.all(
arr.map((item)=>{
return varyant.updateMany({"_id": item.id }, {"$set": { "color":"value" } },
{multi:true});
})).then(function(results){
});
this function success, write color:"value"
but change
return varyant.updateMany({"_id": item.id }, {"$set":{ "color":{ $in: arr.color } } },
nodejs output:
(node:62738) UnhandledPromiseRejectionWarning: CastError: Cast to string failed for value "{ '$in': [ 'a', 'b' ] }" at path "color"
Where am I making a mistake?
$in is not a insert operator is a select operator
You could change the arr array with some easy suitable format
const arr = [{
id: ['5e6e9b0668fcbc7bce2097ac', '5e6e9b0e68fcbc7bce2097af'],
color: ['a', 'b']
}];
const new_arr = arr[0].id.map((id,i)=>({id,color:arr[0].color[i]}));
//[{id,color}]
Promise.all(
new_arr.map((item, i) => {
return varyant.updateMany({
"_id": item.id
}, {
"$set": {
"color": item.color,
}
}, {
multi: true
});
})).then(function(results) {
});
I have a json array with different key values and need to add a ServerUrl to the beginning of all node values using a loop without writing multiple statements to do that by using javascript:
"Urls": [
{ "getCar": "/getAllCars" },
{ "getPerson": "/getAllPersons" },
{ "getBook": "/getAllBooks" }
],
"ServerUrl": "http://192.168.1.1:3000"
The expected result must be:
"Urls": [
{ "getCar": "http://192.168.1.1:3000/getAllCars" },
{ "getPerson": "http://192.168.1.1:3000/getAllPersons" },
{ "getBook": "http://192.168.1.1:3000/getAllBooks" }
],
Any advice would be appreciated.
You can use map to map your objects to new objects. Those objects have a single property, which you can get with Object.keys. The new object can get that same property name using the computed property name feature:
var obj = {
"Urls": [
{ "getCar": "/getAllCars" },
{ "getPerson": "/getAllPersons" },
{ "getBook": "/getAllBooks" }
],
"ServerUrl": "http://192.168.1.1:3000"
};
var urls = obj.Urls.map(o => Object.keys(o).map(k => ({ [k]: obj.ServerUrl + o[k] }))[0]);
console.log(urls);
const jsonVal = {
"Urls": [
{ "getCar": "/getAllCars" },
{ "getPerson": "/getAllPersons" },
{ "getBook": "/getAllBooks" }
],
"ServerUrl": "http://192.168.1.1:3000"
}
const result = jsonVal.Urls.map(val =>
Object.keys(val).reduce((resultObj, endpointKey) => {
resultObj[endpointKey] = `${jsonVal.ServerUrl}${val[endpointKey]}`;
return resultObj;
}, {})
);
Try (where your data are in d)
d.Urls.forEach( (x,i,a,k=Object.keys(x)[0]) => x[k] = d.ServerUrl + x[k]);
let d = {
"Urls": [
{ "getCar": "/GetAllGroupCustomers" },
{ "getPerson": "/getAllItems" },
{ "getBook": "/GetAllCustomers" }
],
"ServerUrl": "http://192.168.1.1:3000"
}
d.Urls.forEach( (x,i,a,k=Object.keys(x)[0]) => x[k] = d.ServerUrl + x[k]);
console.log(d);
A version that modifies your own object
var obj = {
"Urls": [
{ "getCar": "/getAllCars" },
{ "getPerson": "/getAllPersons" },
{ "getBook": "/getAllBooks" }
],
"ServerUrl": "http://192.168.1.1:3000"
};
obj.Urls.forEach(o => o[Object.keys(o)[0]] = `${obj.ServerUrl}${o[Object.keys(o)[0]]}`);
console.log(obj);
I am trying to format a string to produce a new string in the correct format:
I have the following strings (left) which should be formatted to match (right):
[ 'xx9999', 'XX-99-99' ],
[ '9999xx', '99-99-XX' ],
[ '99xx99', '99-XX-99' ],
[ 'xx99xx', 'XX-99-XX' ],
[ 'xxxx99', 'XX-XX-99' ],
[ '99xxxx', '99-XX-XX' ],
[ '99xxx9', '99-XXX-9' ],
[ '9xxx99', '9-XXX-99' ],
[ 'xx999x', 'XX-999-X' ],
[ 'x999xx', 'X-999-XX' ],
[ 'xxx99x', 'XXX-99-X' ],
[ 'x99xxx', 'X-99-XXX' ],
[ '9xx999', '9-XX-999' ],
[ '999xx9', '999-XX-9' ]
I have tried the following but cannot get it to work correctly:
const formatLp = (userInput) => {
if (userInput) {
return userInput.toUpperCase().match(/[a-z]+|[^a-z]+/gi).join('-');
}
}
This works for some of them, such as 99xxx9 but not others such as xx9999
any help would be appreciated.
Use .replace twice - once to insert a - between 4 repeated digits/non-digits, and once to insert a - between digits and alphabetical characters:
const arr = [
[ 'xx9999', 'XX-99-99' ],
[ '9999xx', '99-99-XX' ],
[ '99xx99', '99-XX-99' ],
[ 'xx99xx', 'XX-99-XX' ],
[ 'xxxx99', 'XX-XX-99' ],
[ '99xxxx', '99-XX-XX' ],
[ '99xxx9', '99-XXX-9' ],
[ '9xxx99', '9-XXX-99' ],
[ 'xx999x', 'XX-999-X' ],
[ 'x999xx', 'X-999-XX' ],
[ 'xxx99x', 'XXX-99-X' ],
[ 'x99xxx', 'X-99-XXX' ],
[ '9xx999', '9-XX-999' ],
[ '999xx9', '999-XX-9' ]
];
arr.forEach(([str]) => {
const result = str.toUpperCase()
.replace(/\d{4}|\D{4}/, substr => `${substr.slice(0, 2)}-${substr.slice(2)}`)
.replace(/[a-z]{4}|\d(?=[a-z])|[a-z](?=\d)/gi, '$&-');
console.log(result);
});
You can also do it by matching and then joining - match 3 non-digits, or 3 digits, or 1-2 non-digits, or 1-2 digits:
const arr = [
[ 'xx9999', 'XX-99-99' ],
[ '9999xx', '99-99-XX' ],
[ '99xx99', '99-XX-99' ],
[ 'xx99xx', 'XX-99-XX' ],
[ 'xxxx99', 'XX-XX-99' ],
[ '99xxxx', '99-XX-XX' ],
[ '99xxx9', '99-XXX-9' ],
[ '9xxx99', '9-XXX-99' ],
[ 'xx999x', 'XX-999-X' ],
[ 'x999xx', 'X-999-XX' ],
[ 'xxx99x', 'XXX-99-X' ],
[ 'x99xxx', 'X-99-XXX' ],
[ '9xx999', '9-XX-999' ],
[ '999xx9', '999-XX-9' ]
];
arr.forEach(([str]) => {
const result = str.toUpperCase()
.match(/[a-z]{3}|\d{3}|[a-z]{1,2}|\d{1,2}/gi)
.join('-');
console.log(result);
});
I've just implemented this using Stack. Here is the function. You just need to pass the string to this function.
const convert = (str) => {
let stack = str.split('').reduce((newArr, char, index) => {
if(index !== 0 && newArr[newArr.length-1] !== char) {
newArr.push('-');
newArr.push(char);
return newArr;
} else {
newArr.push(char);
return newArr;
}
},[])
return stack.join('').toUpperCase();
}
// Here you can check this in action
const convert = (str) => {
let stack = str.split('').reduce((newArr, char, index) => {
if(index !== 0 && newArr[newArr.length-1] !== char) {
newArr.push('-');
newArr.push(char);
return newArr;
} else {
newArr.push(char);
return newArr;
}
},[])
return stack.join('').toUpperCase();
}
const strings = [ 'xx9999','9999xx','99xx99','xx99xx','xxxx99','99xxxx','99xxx9','9xxx99','xx999x','x999xx','xxx99x','x99xxx','9xx999','999xx9',];
strings.map(string => console.log(convert(string)))
My data looks like:
[ [ '0s', '0.200s' ],
[ '0.200s', '0.600s' ],
[ '1.600s', '2.500s' ],
[ '3.500s', '3.900s' ],
[ '3.900s', '4.400s' ],
[ '4.400s', '4.600s' ],
[ '4.600s', '4.700s' ],
[ '4.700s', '5.200s' ],
[ '5.200s', '5.400s' ],
[ '5.400s', '5.800s' ],
[ '5.800s', '6.100s' ],
[ '6.100s', '6.800s' ],
[ '6.800s', '7s' ],
[ '7s', '7.300s' ],
[ '7.300s', '7.500s' ]
]
The first element ends at 0.200s which is where the second element begins. So I want those 2 to combine to be ['0s', '0.600s'].
The next element doesn't start where this one ends, so it should continue on. Ultimately, the result should look like:
[ [ '0s', '0.600s' ],
[ '1.600s', '2.500s' ],
[ '3.500s', '7.500s' ]
]
I am trying to do it recursively, but it's giving errors. Here's my function:
function combineStartsEnds(timecodes) {
if (timecodes[0][1] === timecodes[1][0]) {
let combined = [
[timecodes[0][0], timecodes[1][1]]
].concat(_.slice(timecodes, 2));
return combineStartsEnds(combined);
} else {
return timecodes[0].concat(combineStartsEnds(_.slice(timecodes, 1)));
}
};
This gives an error:
TypeError: Cannot read property '0' of undefined
Any ideas on how to accomplish this?
You are missing brackets here, this:
return timecodes[0].concat(...)
must be:
return [timecodes[0]].concat(...)
Additionally you need a base case to end the recursion:
function combineStartsEnds(timecodes) {
if(!timecodes.length) return [];
How I would do that:
function combineStartsEnds(timecodes) {
const result = []; let previous = [];
for(const [start, end] of timecodes) {
if(start === previous[/*end*/ 1]) {
previous[/*end*/ 1] = end;
} else {
result.push(previous = [start, end]);
}
}
return result;
}
You can also do this with reduce.
const times = [ [ '0s', '0.200s' ],
[ '0.200s', '0.600s' ],
[ '1.600s', '2.500s' ],
[ '3.500s', '3.900s' ],
[ '3.900s', '4.400s' ],
[ '4.400s', '4.600s' ],
[ '4.600s', '4.700s' ],
[ '4.700s', '5.200s' ],
[ '5.200s', '5.400s' ],
[ '5.400s', '5.800s' ],
[ '5.800s', '6.100s' ],
[ '6.100s', '6.800s' ],
[ '6.800s', '7s' ],
[ '7s', '7.300s' ],
[ '7.300s', '7.500s' ]
];
const merged = times.reduce((acc, [t3, t4]) => {
const [t1, t2] = acc[acc.length - 1] || [null, null];
if (t2 === t3) {
acc.pop();
acc.push([t1, t4]);
} else {
acc.push([t3, t4]);
}
return acc;
}, []);
console.log(merged);
You can also try below method to get your desired result.
(1) Flatten the array, you will get
arr.flat()
["0s", "0.200s", "0.200s", "0.600s", "1.600s", "2.500s", "3.500s", "3.900s", "3.900s", "4.400s", "4.400s", "4.600s", "4.600s", "4.700s", "4.700s", "5.200s", "5.200s", "5.400s", "5.400s", "5.800s", "5.800s", "6.100s", "6.100s", "6.800s", "6.800s", "7s", "7s", "7.300s", "7.300s", "7.500s"]
(2) Filter and remove elements if same exists before and after it's position, you will get
arr.flat().filter((d,i,c) => d != c[i-1] && d != c[i+1])
["0s", "0.600s", "1.600s", "2.500s", "3.500s", "7.500s"]
(3) Reduce the above result to the format you need
arr.flat()
.filter((d,i,c) => d != c[i-1] && d != c[i+1])
.reduce((res, d, i, c) => (i%2 == 0 && res.push([d, c[i+1]]) , res) , [])
[["0s", "0.600s"]
["1.600s", "2.500s"]
["3.500s", "7.500s"]]
How about using a Map():
const data = [
['0s', '0.200s'],
['0.200s', '0.600s'],
['1.600s', '2.500s'],
['3.500s', '3.900s'],
['3.900s', '4.400s'],
['4.400s', '4.600s'],
['4.600s', '4.700s'],
['4.700s', '5.200s'],
['5.200s', '5.400s'],
['5.400s', '5.800s'],
['5.800s', '6.100s'],
['6.100s', '6.800s'],
['6.800s', '7s'],
['7s', '7.300s'],
['7.300s', '7.500s']
];
var data_map = new Map(data);
for (var [key, value] of data_map) {
while (data_map.has(value)) {
var new_value = data_map.get(value);
data_map.set(key, new_value);
data_map.delete(value);
value = new_value;
}
}
data_map.forEach((value, key) => console.log(`[${key}, ${value}]`));
You could reduce the array with a single loop by checking the values and update either the last array or push a new array to the result set.
var data = [['0s', '0.200s'], ['0.200s', '0.600s'], ['1.600s', '2.500s'], ['3.500s', '3.900s'], ['3.900s', '4.400s'], ['4.400s', '4.600s'], ['4.600s', '4.700s'], ['4.700s', '5.200s'], ['5.200s', '5.400s'], ['5.400s', '5.800s'], ['5.800s', '6.100s'], ['6.100s', '6.800s'], ['6.800s', '7s'], ['7s', '7.300s'], ['7.300s', '7.500s']],
combined = data.reduce((r, [a, b]) => {
var last = r[r.length - 1];
if (last && a === last[1]) {
last[1] = b;
} else {
r.push([a, b]);
}
return r;
}, []);
console.log(combined);
.as-console-wrapper { max-height: 100% !important; top: 0; }
One way to do it using recursion –
const start = ([ a, b ]) =>
a
const end = ([ a, b ]) =>
b
const join = ([ a, b, ...rest ]) =>
// base: no `a`
a === undefined
? []
// inductive: some `a`
: b === undefined
? [ a ]
// inductive: some `a` and some `b` (joinable)
: end (a) === start (b)
? join ([ [ start (a), end (b) ], ...rest ])
// inductive: some `a` and some `b` (non-joinable)
: [ a, ...join ([ b, ...rest ]) ]
const data =
[ [ '0s', '0.200s' ]
, [ '0.200s', '0.600s' ]
, [ '1.600s', '2.500s' ]
, [ '3.500s', '3.900s' ]
, [ '3.900s', '4.400s' ]
, [ '4.400s', '4.600s' ]
, [ '4.600s', '4.700s' ]
, [ '4.700s', '5.200s' ]
, [ '5.200s', '5.400s' ]
, [ '5.400s', '5.800s' ]
, [ '5.800s', '6.100s' ]
, [ '6.100s', '6.800s' ]
, [ '6.800s', '7s' ]
, [ '7s', '7.300s' ]
, [ '7.300s', '7.500s' ]
]
console.log (join (data))
// [ [ '0s', '0.600s' ]
// , [ '1.600s', '2.500s' ]
// , [ '3.500s', '7.500s' ]
// ]