Group two arrays based off an if statement? - javascript

Very green to programming.
I have two arrays, one with numbers and one with text.
var time = [20,40,60,30,36];
var name = ["jon","tim","jon","jon","andy"];
What I want to do is something like:
If name == jon take all corresponding numbers(time) and group them. So it would take name[0] and time[0] and group it as well as jon[2] and time [2] and put it in the same group and so on and so forth. So I assume I would need to create new arrays but I'm not sure how to make the if statement without actually specifying the place in the array.

If you are looking for an array as result set, you could use a hash table for the indices of the result set.
var time = [20, 40, 60, 30, 36],
names = ["jon", "tim", "jon", "jon", "andy"],
groups = {},
result = [];
names.forEach(function (n, i) {
if (!(n in groups)) {
groups[n] = result.push([n, 0]) - 1;
}
result[groups[n]][1] += time[i];
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Loop over your names and use the same index to get the times. Put them in to a new object, setting the starting value of 0 if that name hasn't yet been used.
var arr_time = [20,40,60,30,36];
var arr_name = ["jon","tim","jon","jon","andy"];
var rst = {};
arr_name.forEach(function( person, index ){
rst[ person] = rst[ person] || 0;
rst[ person] += arr_time[ index ];
});
console.log( rst );

You can reach your desired result with Array#reduce.
let time = [20, 40, 60, 30, 36];
let array = ["jon", "tim", "jon", "jon", "andy"];
const check = (name, arr) => {
return { [name]: arr.reduce((s, a, i) => {
a == name ? s.push(time[i]) : null;
return s;
}, [])};
}
console.log(check('jon', array));
console.log(check('tim', array));
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can group the items using Array#reduce.
If you want the sums:
var time = [20,40,60,30,36];
var names = ["jon","tim","jon","jon","andy"];
var result = names.reduce(function(o, name, i) {
o[name] = (o[name] || 0) + time[i];
return o;
}, {});
console.log(result);
If you want to group them in arrays:
var time = [20,40,60,30,36];
var names = ["jon","tim","jon","jon","andy"];
var result = names.reduce(function(o, n, i) {
o[n] = o[n] || [];
o[n].push(time[i]);
return o;
}, {});
console.log(result);

var time = [20,40,60,30,36];
var names = ["jon","tim","jon","jon","andy"];
var final = names.reduce(function(a, b, i) {
if(!(a.hasOwnProperty(b))) {
a[b] = 0;
}
a[b] = a[b] + time[i];
return a;
}, {});
Reduce check how reduce works it helps you to understand in better way.
Hope it helps you !

Here is a solution using for loop. For each index in the names array, I am checking if the result object has that name. If it has that name I am adding the time corresponding to that index, otherwise I am adding that name to that result object and adding time.
const times = [20,40,60,30,36];
const names = ["jon","tim","jon","jon","andy"];
var result = {};
for(var i = 0 ; i < names.length ; ++i){
let name = names[i];
let time = times[i];
if(result[name] !== undefined){
result[name].push(time);
} else {
result[name] = [time];
}
}
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here is a solution using array reduce.
var times = [20,40,60,30,36];
var names = ["jon","tim","jon","jon","andy"];
var result = names.reduce((obj, name, index) => {
obj[name] = obj[name] || [];
obj[name].push(times[index]);
return obj;
},{});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Inconsistency, when returning index of duplicate values

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);

Javascript: key/value storage in object with multilevel nesting

I have been given two arrays:-
var keys = ['a.b', 'a.c.d', 'a.e', 'h[0]'];
var values = [10, 20, {}, 40];
The output that I want is:-
{
a: {
b: 10,
c: {
d: 20
},
e: {}
},
h: [40]
}
What I have tried so far is
let constructObject = (keys, values) => {
let output = {};
for(let i = 0; i<keys.length; i++) {
let props = keys[i].split('.');
for(let j=0; j<props.length;j++) {
if(props.length > (j+ 1)) {
if(output[props[j]] == undefined) {
output[props[j]] = {};
}
} else {
output[props[j]] = values[i];
}
}
}
return output;
}
The above code is not nesting deeper. I tried to store nested level key also using for loop but could not get any way to store keys, As javascript only gives way to store value not nested level keys.
You could separate the pathes into smaller parts, like properties and indices and build new object by respecting the next key and decide if an array or an object has to be taken.
function setValue(target, keys, value) {
const
isWrapped = s => s.startsWith('[') && s.endsWith(']'),
unwrap = s => isWrapped(s) ? s.slice(1, -1) : s,
path = keys.match(/\[[^\]+]\]|[^\.\[\]]+/g),
last = path.pop();
path
.reduce((o, k, i, { [i + 1]: next = last }) =>
o[unwrap(k)] = o[unwrap(k)] || (isWrapped(next) ? [] : {}), target)
[unwrap(last)] = value;
}
var keys = ['a.b', 'a.c.d', 'a.e', 'h[0]'],
values = [10, 20, {}, 40],
i,
l = keys.length,
result = {};
for (i = 0; i < l; i++) setValue(result, keys[i], values[i]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Compare array items (items are arrays) if items in same position are equals

I'm using Adobe ExtendScript Toolkit to debug. I'm coding for InDesign and really don't have deep JavaScript knowledge (and don't know what ES6 means).
ExtendScript doesn't accept let as reserved word. Maybe something about this ES6 you're meaning?
I need to compare all the items in an array and join some of them if one of its child are the same. Let me explain:
Based on the following array:
var array = [[1,"luis"] , [2,"felipe"] , [2,"erick"] , [2,"mark"] , [3,"dustin"]]
So, I want to get as result this array:
var array = [[1,"luis"] , [2,"felipe; erick; mark"] , [3,"dustin"]]
How can I compare the array items to get the desired result?
I already tried two for loops and a while.
Maybe I made them wrong. Because of that, I'm here to ask you guys.
If I use this:
for (var i=0; i<array.length-1; i++) {
for (var j=i+1; j<array.length; j++) {
if (array[i][0] == array[j][0]) {
array[i][1] = array[i][1] + "; " + array[j][1];
}
}
}
I have all results. Like this:
1,luis
2,felipe; erick; mark
2,erick; mark
2,mark
3,dustin
Use Object.entries and reduce.
var array = [[1,"luis"] , [2,"felipe"] , [2,"erick"] , [2,"mark"] , [3,"dustin"]];
const res = Object.entries(array.reduce((a, [n, s]) => (a[n] = a[n] ? a[n] + "; " + s : s, a), {}));
console.log(res);
.as-console-wrapper { max-height: 100% !important; top: auto; }
You can use Object.entries() and Array's .reduce() methods to get the desired output:
const data = [[1,"luis"] , [2,"felipe"] , [2,"erick"] , [2,"mark"] , [3,"dustin"]];
const result = Object.entries(data.reduce((r, [key, val]) => {
r[key] = key in r ? [r[key].toString() + "; " + val] : val;
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use reduce and map
First group by first element in subarray
map entries to desired format
var array = [[1,"luis"] , [2,"felipe"] , [2,"erick"] , [2,"mark"] , [3,"dustin"]]
let op = array.reduce((op,inp)=>{
op[inp[0]] = op[inp[0]] || []
op[inp[0]].push(inp[1])
return op
},{})
let final = Object.entries(op).map(([key,value])=> [+key,value.join('; ')])
console.log(final)
You can use reduce
var array = [
[1, "luis"],
[2, "felipe"],
[2, "erick"],
[2, "mark"],
[3, "dustin"]
]
const result = array.reduce(function(re, arr) {
const item = re.find(function(o) {
return o[0] === arr[0]
})
typeof item === 'undefined' ? re.push(arr) : (item[1] = item[1] + ';' + arr[1])
return re
}, [])
console.log(result)
Here is the solution below
var array = [[1,"luis"] , [2,"felipe"] , [2,"erick"] , [2,"mark"] , [3,"dustin"]]
function mergeArrayBySameId(){
let old = [];
let mergedArr = [];
array.map(function(curr, i){
let tmp = "";
let current = array[i];
let prev = ( i === 0 ) ? [] : array[i-1];
if( current[0] === prev[0] ){
tmp = current[0];
mergedArr[0] = tmp;
if( !mergedArr.includes( prev[1] ) ){
mergedArr.push( prev[1] );
}
mergedArr.push( current[1] );
}
old = prev;
});
let mergedStr = ""
let mergedArrId = mergedArr[0];
mergedArr.map(function(val){
if( typeof val !== 'number' ){
mergedStr += val + "; ";
}
});
mergedArr = [];
mergedArr[0] = mergedArrId;
mergedArr[1] = mergedStr;
function checkId(id){
return mergedArr[0] != id[0];
}
let filterArray = array.filter(checkId);
let finalArray = filterArray.concat([mergedArr]).sort();
return finalArray;
}
console.log( mergeArrayBySameId() );
Thank you all for your suggestions.
I'm sorry because I'm very beginner and just have familiarity with javascript while coding for Adobe software automation.
I found a way using:
var array = [[1,"luis"] , [2,"felipe"] , [2,"erick"] , [2,"mark"] , [3,"dustin"]];
for (var i=0; i<array.length-1; i++) {
var j = i+1;
while (j < array.length) {
if (array[i][0] == array[j][0]) {
array[i][1] = array[i][1] + "; " + array[j][1];
array.splice(j , 1);
j = i;
}
j++;
}
}
alert(array.join("\r"));
let arr = [
[1, "luis"],
[3, "felipe"],
[2, "erick"],
[3, "mark"],
[3, "dustin"]
];
let res = arr.reduce((acc,cur) => {
const item = acc.find((obj) => {
if(obj[0] === cur[0]){
obj.push(cur[1]);
return obj
}
});
if(!item)
acc.push(cur);
return acc
},[]);

how to filter all string sequence in array using javascript

I have a large array, and I want to filter it based on a string I pass it. This string could be one or two characters, up to an entire string.
Here's an example array:
var data = ["bourbon", "beer", "electric"]
If I pass e, I want the result ["electric", "beer"].
How can I achieve this functionality?
Use filter with includes:
var data = ["bourbon", "beer", "electric"];
const selectByLetter = l => data.filter(s => s.includes(l));
console.log(selectByLetter("e"));
.as-console-wrapper { max-height: 100% !important; top: auto; }
ES5 syntax:
var data = ["bourbon", "beer", "electric"];
var selectByLetter = function(l) {
return data.filter(function(s) {
return s.indexOf(l) > -1;
});
}
console.log(selectByLetter("e"));
.as-console-wrapper { max-height: 100% !important; top: auto; }
you can use underscore.
var data = ["bourbon","beer", "electric"]
var filtered = [];
var filter = function(value) {
filtered = _.filter(data, function(el) {
return el.indexOf(value)
})
return filtered;
}
console.log('filtered',filter('e'));
var data = ["bourbon","beer", "electric"]
var result = data.filter(c => /e/i.test(c))
console.log('data',result);
For an O(N) solution instead of O(N^2), use a Set instead (Set.has is O(1), whereas String.prototype.includes is O(N)):
const data = ["bourbon", "beer", "electric"];
const setByData = data.reduce((a, str) => {
a[str] = new Set(str);
return a;
}, {});
console.log(
Object.entries(setByData)
.filter(([, set]) => set.has('e'))
.map(([str]) => str)
);
products_name = ['ebay','eaby','ebb','ebbe','eaab','eeb']
search_options = []
const searched_word = "eb";
for (const key in products_name)
{
const search_count = products_name[key].search(new RegExp(searched_word, "i"));
if (search_count != -1)
{
search_options.push(products_name[key])
}
}
console.log(search_options)

JS calculate mean of same elements in 2d array

I've got a 'table' of two columns represented as an array. The first column are numbers from 1 to 20 and they are labels, the second column are the corresponding values (seconds):
my_array = [ [ 3,4,5,3,4,5,2 ],[ 12,14,16,11,12,10,20 ] ];
I need the mean (average) for each label:
my_mean_array = [ [ 2,3,4,5 ],[ 20/1, (12+11)/2, (14+12)/2, (16+10)/2 ] ];
// edit: The mean should be a float - the notion above is just for clarification.
// Also the number 'labels' should remain as numbers/integers.
My try:
var a = my_array[0];
var b = my_array[1];
m = [];
n = [];
for( var i = 0; a.length; i++){
m[ a[i] ] += b[i]; // accumulate the values in the corresponding place
n[ a[i] ] += 1; // count the occurences
}
var o = [];
var p = [];
o = m / n;
p.push(n);
p.push(o);
How about this (native JS, will not break on older browsers):
function arrayMean(ary) {
var index = {}, i, label, value, result = [[],[]];
for (i = 0; i < ary[0].length; i++) {
label = ary[0][i];
value = ary[1][i];
if (!(label in index)) {
index[label] = {sum: 0, occur: 0};
}
index[label].sum += value;
index[label].occur++;
}
for (i in index) {
if (index.hasOwnProperty(i)) {
result[0].push(parseInt(i, 10));
result[1].push(index[i].occur > 0 ? index[i].sum / index[i].occur : 0);
}
}
return result;
}
FWIW, if you want fancy I've created a few other ways to do it. They depend on external libraries and are very probably an order of magnitude slower than a native solution. But they are nicer to look at.
It could look like this, with underscore.js:
function arrayMeanUnderscore(ary) {
return _.chain(ary[0])
.zip(ary[1])
.groupBy(function (item) { return item[0]; })
.reduce(function(memo, items) {
var values = _.pluck(items, 1),
toSum = function (a, b) { return a + b; };
memo[0].push(items[0][0]);
memo[1].push(_(values).reduce(toSum) / values.length);
return memo;
}, [[], []])
.value();
}
// --------------------------------------------
arrayMeanUnderscore([[3,4,5,3,4,5,2], [12,14,16,11,12,10,20]]);
// -> [[2,3,4,5], [20,11.5,13,13]]
or like this, with the truly great linq.js (I've used v2.2):
function arrayMeanLinq(ary) {
return Enumerable.From(ary[0])
.Zip(ary[1], "[$, $$]")
.GroupBy("$[0]")
.Aggregate([[],[]], function (result, item) {
result[0].push(item.Key());
result[1].push(item.Average("$[1]"));
return result;
});
}
// --------------------------------------------
arrayMeanLinq([[3,4,5,3,4,5,2], [12,14,16,11,12,10,20]]);
// -> [[3,4,5,2], [11.5,13,13,20]]
As suspected, the "fancy" implementations are an order of magnitude slower than a native implementation: jsperf comparison.
var temp = {};
my_array[0].map(function(label, i) {
if (! temp[label])
{
temp[label] = [];
}
temp[label].push(my_array[1][i]);
});
var result = [ [], [] ];
for (var label in temp) {
result[0].push(label);
result[1].push(
temp[label].reduce(function(p, v) { return p + v }) / temp[label].length
);
}
This function do not sort the resulted array like in your result example. If you need sorting, just say me and i will add it.
function getMeanArray(my_array)
{
m = {}; //id={count,value}
for( var i = 0; i<my_array[0].length; i++){
if (m[my_array[0][i]]===undefined)
{
m[my_array[0][i]]={count:0, value:0};
}
m[ my_array[0][i] ].value += my_array[1][i]; // accumulate the values in the corresponding place
m[ my_array[0][i] ].count++; // count the occurences
}
var my_mean_array=[[],[]];
for (var id in m)
{
my_mean_array[0].push(id);
my_mean_array[1].push(m[id].count!=0?m[id].value/m[id].count:0);
}
return my_mean_array;
}

Categories