I am looking to replace nested for loop implementation with array helpers for optimization,
The function returns string from testArray, which contains the highest priority as per priorityArray.
const arr1 = ["A_COUNTY","B_STATE","C_COUNTRY", "D_CONTINENT","E_WORLD"];
const arr2 = ["X_COUNTY","Y_STATE","Z_PLANET"];
const priorityArray = ["CONTINENT","COUNTRY","STATE","COUNTY"];
function findPriorityElement(testArray:string[])
{
for (let i = 0; i <priorityArray.length; i++)
for (let j = 0; j <testArray.length; j++) {
if (testArray[j].includes(priorityArray[i]))
return testArray[j];
}
return "";
}
console.log(findPriorityElement(arr1)); // Result: "D_CONTINENT"
console.log(findPriorityElement(arr2)); // Result: "Y_STATE"
Any leads is appreciated.
You could use find() instead of the inner for loop
const arr1 = ["A_COUNTY", "B_STATE", "C_COUNTRY", "D_CONTINENT", "E_WORLD"];
const arr2 = ["X_COUNTY", "Y_STATE", "Z_PLANET"];
const priorityArray = ["CONTINENT", "COUNTRY", "STATE", "COUNTY"];
function findPriorityElement(testArray) {
for (p of priorityArray) {
const match = testArray.find(e => e.includes(p));
if (match) {
return match;
}
}
}
console.log(findPriorityElement(arr1)); // Result: "D_CONTINENT"
console.log(findPriorityElement(arr2)); // Result: "Y_STATE"
const arr1 = ["A_COUNTY", "B_STATE", "C_COUNTRY", "D_CONTINENT", "E_WORLD"];
const arr2 = ["X_COUNTY", "Y_STATE", "Z_PLANET"];
const priorityArray = ["CONTINENT", "COUNTRY", "STATE", "COUNTY"];
const findPriorityElement = testArray => {
for (const priorityElement of priorityArray) {
const elem = testArray.find(testElement => testElement.includes(priorityElement));
if (elem) {
return elem;
}
}
};
console.log(findPriorityElement(arr1)); // Result: "D_CONTINENT"
console.log(findPriorityElement(arr2)); // Result: "Y_STATE"
Related
I am using node to convert an array to object, I have an array looks like this
[
'items[0].book=Book1',
'items[0].color=Red',
'items[0].bookCode=#1',
'items[1].book=Book2',
'items[1].color=Yellow',
'items[1].bookCode=#2',
'items[2].book=Book3',
'items[2].color=Blue',
'items[2].bookCode=#3',
...
]
I am trying to convert it to be objets in one array
items:[
{
book: "Book1",
color: "Red",
bookCode: "#1"
},
{
book: "Book2",
color: "Yellow",
bookCode: "#2"
},
...
]
I found it is easy to conver it uses a 3rd party lib like setKeypath/set,
const obj = {};
const arr = [items......(like above)]
arr.forEach((val => {
if (val.startsWith('items[')) {
const splitWord = item.split('=');
setKeypath(obj, splitWord[0], splitWord[1]);
}
});
I am seeking a way if it can be done the same output with es6, so I don't really need a library. Thanks
const items = [
"items[0].book=Book1",
"items[0].color=Red",
"items[0].bookCode=#1",
"items[1].book=Book2",
"items[1].color=Yellow",
"items[1].bookCode=#2",
"items[2].book=Book3",
"items[2].color=Blue",
"items[2].bookCode=#3"
];
let res = [];
let currId = "";
let currItem = null;
for (let i = 0; i < items.length; i++) {
let parts = items[i].split(".");
if (currId!==parts[0] && currItem) { //new item
res.push(currItem)
currId = parts[0];
}
if (!currItem)
currItem = {};
let keyValue = parts[1].split("=");
currItem[keyValue[0]] = keyValue[1]
}
console.log({items: res})
You may first find all values by regex, and insert the attribute to each corresponding element one by one. This approach works for whatever ordering the array is, and whatever attributes there are, as long as each element follow the same pattern.
let items = [
"items[1].bookCode=#2",
"items[0].book=Book1",
"items[0].bookCode=#1",
"items[1].book=Book2",
"items[2].bookCode=#3",
"items[1].color=Yellow",
"items[2].book=Book3",
"items[2].color=Blue",
"items[0].color=Red",
"items[4].test=test!"
];
let indexPattern = /\[(\d*)\]/;
let attrPattern = /\.(.*)=/;
let valuePattern = /=(.*)/;
let obj = Object.values(
items.reduce((obj, element) => {
let index = element.match(indexPattern)[1];
let attr = element.match(attrPattern)[1];
let value = element.match(valuePattern)[1];
if (!obj.hasOwnProperty(index)) obj[index] = {};
obj[index][attr] = value;
return obj;
}, {})
);
console.log(obj);
[
'items[0].book=Book1',
'items[0].color=Red',
'items[0].bookCode=#1',
'items[1].book=Book2',
'items[1].color=Yellow',
'items[1].bookCode=#2',
'items[2].book=Book3',
'items[2].color=Blue',
'items[2].bookCode=#3',
].reduce((acc, str) => {
const index = Number(str.slice(str.indexOf('[') + 1, str.indexOf(']')));
if (!acc[index]) {
acc[index] = {};
}
const entry = [str.slice(str.indexOf('.') + 1, str.indexOf('=')), str.slice(str.indexOf('=') + 1)];
acc[index][entry[0]] = entry[1];
return acc;
}, []);
Here I pick apart the string you're given based on the consistent format, grab the index, key, and value, and then just use Array#reduce to do the work of putting the array together.
Documentation:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
I think a smattering of regex would do the trick:
const ar = [
'items[0].book=Book1',
'items[0].color=Red',
'items[0].bookCode=#1',
'items[1].book=Book2',
'items[1].color=Yellow',
'items[1].bookCode=#2',
'items[2].book=Book3',
'items[2].color=Blue',
'items[2].bookCode=#3'
]
const result = [];
ar.forEach(item => {
const index = parseInt(item.match(/\[([0-9]+)\]/)[1]);
const params = item.split(".")[1].split("=");
if(!result[index])
result[index] = {}
result[index][params[0]] = params[1];
})
console.log(result)
Note that item.match(/\[([0-9]+)\]/) matches the number inside your brackets. match returns an array where 1 is the index of the actual value between the brackets.
I'm recreating the filter, map, find functions in js. And I have a function pipe, that takes the given array and passes it trough an array of functions such as filter, map etc.
These are my functions:
const filter = (arr, callback) => {
let newArr = [];
let j = 0;
for (let i = 0; i < arr.length; i++) {
if (callback(arr[i])) {
newArr[j] = arr[i];
j++;
}
}
return newArr;
};
const map = (arr, callback) => {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
newArr[i] = callback(arr[i], i);
}
return newArr;
};
const pipe = (arr, callbacks) => {
console.log(arr, "arr");
console.log(callbacks, "callbacks");
};
I can use filter like so, and the function works fine.
const arr = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present']
filter(arr, item => item.length > 6) // returns ["exuberant", "destruction", "present"]
However, when using pipe, I should not pass arr to each function. Instead filter and map should somehow take arr from pipe. But since those functions are being called directly in the pipe call, I do not see how can I achieve that functionality.
const arr = ['spray', 'limit', 'elite', 'exuberant', 'destruction']
pipe(
arr,
[
filter(item => item.length > 6), // returns ["exuberant", "destruction"]
map((item, index) => ({ id: index, name: item })) // returns [{ id: 0, name: 'exuberant' }, { id: 1, name: 'destruction' }]
]
)
// pipe returns [{ id: 0, name: 'exuberant' }, { id: 1, name: 'destruction' }]
Usually filter and map takes 2 params, arr and a callback. But in pipe it takes just the callback.
Any help would be appreciated.
Thanks.
I see that you are trying to implement a concept of functional programming known as pipe.
There's a better way to do what you are trying to achieve.
Instead of passing the array to the pipe function, only pass the map and filter functions to the pipe function and have pipe function return another function that takes the input array and returns the result of executing each function from left to right and passing the input array to each function.
Also change map and filter functions to return another function that takes in the input array as an argument and returns a new array after iterating over the array and passing each each element to the callback function.
const filter = callback => {
return (arr) => {
let newArr = [];
let j = 0;
for (let i = 0; i < arr.length; i++) {
if (callback(arr[i])) {
newArr[j] = arr[i];
j++;
}
}
return newArr;
};
};
const map = callback => {
return (arr) => {
const newArr = [];
for (let i = 0; i < arr.length; i++) {
newArr[i] = callback(arr[i], i);
}
return newArr;
};
};
const pipe = (...funcs) => {
return array => {
return funcs.reduce((acc, curr) => curr(acc), array);
};
};
const arr = ['spray', 'limit', 'elite', 'exuberant', 'destruction'];
const result = pipe(
filter(item => item.length > 6),
map((item, index) => ({ id: index, name: item }))
)(arr);
console.log(result);
there is no easy solution for this since you call the function filter and map directly in the pipe creation (simple functions will execute then)
one thing you can do is change your filter and map functions so they return an object with a method .execute that needs to be called to execute the filter or the map
const filter = (callback) => {
function execute (arr) = {
let newArr = [];
let j = 0;
for (let i = 0; i < arr.length; i++) {
if (callback(arr[i])) {
newArr[j] = arr[i];
j++;
}
}
return newArr;
}
return { // return the object ready to execute
execute
}
};
const map = (callback) => {
function execute (arr) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
newArr[i] = callback(arr[i], i);
}
return newArr;
}
return {
execute
}
};
now if you want to use a filter, do
const arr = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present']
filter(item => item.length > 6).execute(arr)
// returns ["exuberant", "destruction", "present"]
and now the pipe function
const pipe = (arr, callbacks) => {
for (let i = 0; i < callbacks.length; i++) {
callback.execute(arr)
}
};
now use the pipe as wanted
const arr = ['spray', 'limit', 'elite', 'exuberant', 'destruction']
pipe(
arr,
[
filter(item => item.length > 6),
map((item, index) => ({ id: index, name: item }))
]
)
// returns [{ id: 0, name: 'exuberant' }, { id: 1, name: 'destruction' }]
I am trying to remove duplicate JSON Objects from the array in ServiceNow.
Tried below code but it does not remove the duplicate. I want to compare both name & city.
var arr1 = '[{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}]';
var splitlen = JSON.parse(arr1);
alert(splitlen.length);
var uniqueArray = [];
var uniqueJson = {};
for(i=0;i<splitlen.length;i++)
{
if(uniqueArray.indexOf(splitlen[i].name)==-1)
{
uniqueArray.push(splitlen[i]);
}
}
alert(JSON.stringify(uniqueArray));
Expected output :
[{"name":"Pune","city":"India"}]
uniqueArray.indexOf doesn't work because you're comparing objects against strings (splitlen[i].name). Try to use .find() instead:
var arr1 = '[{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}]';
var splitlen = JSON.parse(arr1);
var uniqueArray = [];
var uniqueJson = {};
for(i=0;i<splitlen.length;i++)
{
if(!uniqueArray.find(x => x.name === splitlen[i].name))
{
uniqueArray.push(splitlen[i]);
}
}
console.log(uniqueArray);
or
var arr1 = '[{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}]';
var splitlen = JSON.parse(arr1);
function compare(x){
return x.name === splitlen[i].name;
}
var uniqueArray = [];
var uniqueJson = {};
for(i=0;i<splitlen.length;i++)
{
if(!uniqueArray.find(compare))
{
uniqueArray.push(splitlen[i]);
}
}
console.log(uniqueArray);
you can try this. Also one more thing your array declaration is not right, remove single quotes from array.
var arr1 = [{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}];
function getUniqueListByKey(arr, key) {
return [...new Map(arr.map(item => [item[key], item])).values()]
}
var arr2 = getUniqueListByKey(arr1, "name")
console.log(arr2);
Please try the following example
const arr1 = '[{"name":"Pune","city":"India"},{"name":"Pune","city":"India"}]';
const splitlen = JSON.parse(arr1);
const output = splitlen.reduce((previousValue, currentValue) => {
const { name, city } = currentValue;
const index = previousValue.findIndex(
(entry) => entry.name === name && entry.city === city
);
if (index === -1) {
return [...previousValue, currentValue];
}
return previousValue;
}, []);
console.log(output);
See
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
Put the records in a hashset. If there is collision in the hashset, there is duplicate. This approach is O(n) while comparing all pairs is $O(n^2)$.
I'm trying to get an answer, here's my idea:
Create a function to compare two objects then create a function to get the unique value
function isEquals(obj1, obj2) {
const aProps = Object.getOwnPropertyNames(obj1);
const bProps = Object.getOwnPropertyNames(obj2);
if (aProps.length !== bProps.length) {
return false;
}
for (let j = 0; j < aProps.length; j++) {
const propName = aProps[j];
if (JSON.stringify(obj1[propName]) !== JSON.stringify(obj2[propName])) {
return false;
}
} return true;
}
function getUnique(arr) {
var uniqueArray = [];
for (var item of arr) {
const uniqueItems = arr.filter(i => isEquals(item, i));
if (uniqueItems.length !== 0) {
uniqueArray.push(Object.assign({}, uniqueItems.shift()));
}
arr = arr.filter(i => !isEquals(item, i));
}
return uniqueArray;
}
Hope it helps!
I'm trying to create an algorithm to find duplicate values in a list and return their respective indexes, but the script only returns the correct value, when I have 2 equal elements:
array = [1,2,0,5,0]
result -> (2) [2,4]
Like the example below:
array = [0,0,2,7,0];
result -> (6) [0, 1, 0, 1, 0, 4]
The expected result would be [0,1,4]
Current code:
const numbers = [1,2,0,5,0];
const checkATie = avgList => {
let averages, tie, n_loop, currentAverage;
averages = [... avgList];
tie = [];
n_loop = 0;
for(let n = 0; n <= averages.length; n++) {
currentAverage = parseInt(averages.shift());
n_loop++
for(let avg of averages) {
if(avg === currentAverage) {
tie.push(numbers.indexOf(avg),numbers.indexOf(avg,n_loop))
};
};
};
return tie;
}
console.log(checkATie(numbers));
if possible I would like to know some way to make this code more concise and simple
Use a Set
return [...new Set(tie)]
const numbers1 = [1,2,0,5,0];
const numbers2 = [0,0,2,7,0];
const checkATie = avgList => {
let averages, tie, n_loop, currentAverage;
averages = [... avgList];
tie = [];
n_loop = 0;
for(let n = 0; n <= averages.length; n++) {
currentAverage = parseInt(averages.shift());
n_loop++
for(let avg of averages) {
if(avg === currentAverage) {
tie.push(avgList.indexOf(avg),avgList.indexOf(avg,n_loop))
};
};
};
return [...new Set(tie)]
}
console.log(checkATie(numbers1));
console.log(checkATie(numbers2));
I hope this help you.you can use foreach function to check each item of array
var array = [0,0,2,7,0];
var result = [] ;
array.forEach((item , index)=>{
if(array.findIndex((el , i )=> item === el && index !== i ) > -1 ){
result.push(index)
}
})
console.log(result);
//duplicate entries as an object
checkDuplicateEntries = (array) => {
const duplicates = {};
for (let i = 0; i < array.length; i++) {
if (duplicates.hasOwnProperty(array[i])) {
duplicates[array[i]].push(i);
} else if (array.lastIndexOf(array[i]) !== i) {
duplicates[array[i]] = [i];
}
}
console.log(duplicates);
}
checkDuplicateEntries([1,2,0,5,0]);
// hope this will help
Create a lookup object with value and their indexes and then filter all the values which occurred more than once and then merge all indexes and generate a new array.
const array = [1, 2, 0, 5, 0, 1, 0, 2],
result = Object.values(array.reduce((r, v, i) => {
r[v] = r[v] || [];
r[v].push(i);
return r;
}, {}))
.filter((indexes) => indexes.length > 1)
.flatMap(x => x);
console.log(result);
Trying to find an algorithm that will do the following:
let input = [ 'kooty', 'dlnnoo', 'emor', 'dlnnoo', 'kooty', 'aiprs' ]
function combine(input){
// you should return
[ ['kooty', 'kooty'], ['dlnnoo','dlnnoo'], ['emor'], ['aiprs'] ]
}
I got the answer by using Lodash but i was wondering if there was a way without
function combine(input){
let sortedCity = [];
let finalArr = [];
for(let city in input){
sortedCity.push(input[city].toLowerCase().split('').sort().join(''));
}
let a = lodash.groupBy(sortedCity)
return Object.values(a)
}
combine(input)
let input = [ 'kooty', 'dlnnoo', 'emor', 'dlnnoo', 'kooty', 'aiprs' ]
function combine (input) {
let sorted = input.map(cur => cur.toLowerCase().split('').sort().join(''))
let cache = {} // cache value to index of result array
return sorted.reduce((sum, cur) => {
let index = cache[cur]
if (index !== undefined) {
sum[index].push(cur)
} else {
sum.push([cur])
cache[cur] = sum.length - 1
}
return sum
}, [])
}
combine(input)