create multidimensional array then push another array each those multidimensional array - javascript

is that possible to create a multidimensional array, then push another array on each those multidimensional array ??
lets say the variable
arr = ["apple", "orange", "Avocados", "Tomato", "Tangerine"]
and the output I want is:
[
["a", ["apple", "avocados"] ],
[ "o", ["orange"] ],
["T", ["Tomato", "Tangering"]]
]
the example about to create first initial to new arr multidimensional before the output, we create like this, [[ "a"],["o"],["T"]] and output i want is on above ( the box code )
then check again if that first initial same with a first initial array, push it on those 2d arrays, that is for example, but if array length for others is not same, we should create a function, to use it again late

You could group the data by finding the array with the value or create a new array for the result set.
var array = ["apple", "orange", "avocados", "tomato", "tangerine"],
result = array.reduce((r, s) => {
var temp = r.find(([c]) => c === s[0]);
if (temp) {
temp[1].push(s);
} else {
r.push([s[0], [s]]);
}
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A better structure would be to use a Map and collect all strings to the same starting letter.
var array = ["apple", "orange", "avocados", "tomato", "tangerine"],
result = Array.from(
array.reduce((map, s) => map.set(s[0], [...(map.get(s[0]) || []), s]), new Map)
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

I think your output is too complicated to produce. You can simplify the output format like this:
{
"a" : ["apple", "avocados"],
"o": ["orange"],
"t": ["Tomato", "Tangering"]
}
You can produce output like this with ease with Lodash:
_.groupBy(["apple", "orange", "Avocados", "Tomato", "Tangerine"], function (item) {
return item[0].toLowerCase()
});
Or with iterate the array:
var arr = ["apple", "orange", "Avocados", "Tomato", "Tangerine"];
var output = [];
for (var i = 0 ; i < arr.length ; i++){
if (output[arr[i][0].toLowerCase()] == undefined)
output[arr[i][0].toLowerCase()] = [];
output[arr[i][0].toLowerCase()].push(arr[i]);
}

You can reduce the array to object
var arr = ["apple", "orange", "Avocados", "Tomato", "Tangerine"];
var output = arr.reduce(function(res, item) {
if(Object.keys(res).indexOf(item.charAt(0).toLowerCase()) == -1)
{
res[item.charAt(0).toLowerCase()] = [];
}
res[item.charAt(0).toLowerCase()].push(item);
return res;
},{});
console.log(output);

Yet another alternative using vanilla JavaScript and some functional programming:
const input = ["apple", "orange", "Avocados", "Tomato", "Tangerine"]
// (1) An unique list of lower-cased initials of all given input words
// * Set gives us the unique behavior
const initials = [...new Set (
input.map (([initial]) => initial.toLowerCase ())
)]
const byInitial = ([initial]) => ([initial_]) =>
initial_.toLowerCase () == initial
// (2) This groups each world by their initial
// Iterates each lowered initial and filters the input by each initial
// to build the groups!
const grouped = initials.reduce ((o, initial) =>
[
...o, // <--- this accumulates the new result with the previous one
[
initial,
input.filter (byInitial(initial))
]
], [])
console.log (grouped)
Yet another approach, now using zip:
const input = ["apple", "orange", "Avocados", "Tomato", "Tangerine"]
// (1) An unique list of lower-cased initials of all given input words
// * Set gives us the unique behavior
const initials = [...new Set (
input.map (([initial]) => initial.toLowerCase ())
)]
const byInitial = ([initial]) => ([initial_]) =>
initial_.toLowerCase () == initial
// (2) This builds groups each world by their initial
const groups = initials.map (initial =>
input.filter (byInitial (initial))
)
const zip = (xs, ys) =>
xs.map((x, i) => [x, ys[i]])
// zip builds the pairs, where each one is the initial and the group
const grouped = zip (initials, groups)
console.log (grouped)

Using reduce, create an object with first char of each item as the key and an array of all the items which start with that char as it's value. Then call Object.entries to get the desired output:
const arr = ["apple", "orange", "avocados", "tomato", "tangerine"],
group = Object.entries(arr.reduce((a, i) => ((a[i[0]] = a[i[0]] || []).push(i), a), {}));
console.log(group);

Related

JS string list: transform to partial concatenation [duplicate]

I'm having trouble wrapping my head around this, but let's say there an array with these elements:
["apple", "banana", "pear", "kiwi", "orange"]
I would like to transfer this array into:
["apple", "apple/banana", "apple/banana/pear", "apple/banana/pear/kiwi", "apple/banana/pear/kiwi/orange"]
I need this in JavaScript and I'm not sure how to achieve it.
Please note that I'm currently working with ES5.
Here's a simple implementation of what you're trying to do :
ES5
var input = ["apple", "banana", "pear", "kiwi", "orange"];
var prev = '';
var output = input.map(function (el) {
el = prev + el; prev = el + '/'; return el;
});
console.log(output);
ES6
let input = ["apple", "banana", "pear", "kiwi", "orange"];
let prev= '';
let output = input.map( el => { el = prev + el; prev = el+'/'; return el})
console.log(output)
Array.map() is meant for these problems.
The map() method creates a new array with the results of calling a provided function on every element in the calling array.
And while walking through the array with map you can use join() and slice() to concatenate certain values from an original array.
let input = ["apple", "banana", "pear", "kiwi", "orange"];
let output = input.map((el, index) => {
return (input[index-1]) ? input.slice(0, index+1).join('/') : el;
})
output:
Array [
"apple",
"apple/banana",
"apple/banana/pear",
"apple/banana/pear/kiwi",
"apple/banana/pear/kiwi/orange"
]
Some more explanation on what is happening in those 3 lines:
// let's write it out.
let output = input.map((el, index) => {
// If there is a previous index of this array, we need to join it with this one
if (input[index-1]) {
// all previous values including this one
let a = input.slice(0, index+1)
// concatenate them all with a seperator
let b = a.join('/');
return b;
} else {
// if not just return the element
return el;
}
})
You wrote: Please note that I'm currently working with ES5.
Unfortunately, some people do not understand anymore what is ES5 and suggest ES6 solutions (with arrow function expressions, let statements and constants).
Array.map was added to the ECMA-262 standard in the ECMAScript 5.1 edition. It is fully supported by all modern browsers inclusive IE9.
var input = ["apple", "banana", "pear", "kiwi", "orange"],
output = input.map(function(elem, index)
{
return index > 0 ? input.slice(0, index + 1).join('/') : elem;
});
console.log(JSON.stringify(output, null, '\t'));
var fruits = ["apple", "pear", "orange", "banana"];
var i;
for( i=0; i<fruits.length; i++) {
if (i == 0){
continue;
}
var temp = fruits[i];
fruits[i] = fruits[i-1] + "/" + temp;
}
for( i=0; i<fruits.length; i++) {
print(fruits[i]);
}
Here you go!
Points to remember:
Concatenation Operator
For loop
continue statement
Arrays
var array = ["apple", "banana", "pear", "kiwi", "orange"]
var all = [];
var str ="";
for(var i=0;i< array.length;i++)
{
if(array[i-1]){
str += array[i-1]+'/';
all.push(str+array[i])
}
else all.push(array[i])
}
console.log(all);
Time to .reduce it
This works by creating a new array, and accessing the last placed string and appending a '/' and then the next string current.
yourArray.reduce((newArray, current) => newArray.concat(newArray.length > 0 ? newArray[newArray.length - 1] + '/' + current : current), [])
// long version:
yourArray.reduce((newArray, current) => {
if (newArray.length > 0) {
return newArray.concat(current)
} else {
const previousString = newArray[newArray.length - 1]
return newArray.concat(previousString + '/' + current)
}
}, [])
For the ones that do use ES6 or can transpile the code to ES5 (Using i.e: Babel)
const a = ["a", "b", "c", "d", "e"];
const res = a.map((_, i) => a.slice(0, i+1).join("/"));
console.log(res);

Filter by index of nested array in javascript

I have an array in javascript which contains a number of nested arrays
let data = [
["Apple","Fruit","Red"],
["Pear","Fruit","Green"],
["Orange","Fruit","Orange"],
["Carrot","Vegetable","Orange"],
["Pea","Vegetable","Green"],
["Pumpkin","Vegetable","Orange"]
]
From this array, I wish to create two new arrays. Arr1 is the unique food types (index2) and Arr2is the unique colors (Index 3).
My new arrays should be:
Arr1 = ["Fruit","Vegetable"]
Arr2 = ["Red","Green","Orange"]
I have managed to achieve this by using for each, where I've pushed every second object to an array. I then filter this new array for unique values. This is the code I'm using to do this:
var Foods = []
var Colors = []
for (var key in data) {
Foods.push(data[key][1]);
}
for (var key in data) {
Colors.push(data[key][2]);
}
let Arr1 = [...new Set(Foods)]
let Arr2 = [...new Set(Colors)]
console.log(Arr1)
console.log(Arr2)
Although this works well, as a javascript beginner, I thought there may be a more elegant way to achieve.
For example is it not possible to filter all the unique values of data with an index of [2]?
Your code is fine as it is, the only improvement would be to replace loops with map:
let foods = [...new Set(data.map(d => d[1]))]
let colors = [...new Set(data.map(d => d[2]))]
There's absolutely no need to overcomplicate matters with reduce, destructuring and so on.
If you want it to look slightly more elegant, you can define two utility functions
const item = i => a => a[i]
const uniq = a => [...new Set(a)]
and then
let foods = uniq(data.map(item(1)))
let colors = uniq(data.map(item(2)))
Another option:
const uniq = a => [...new Set(a)]
const zip = (...args) => args[0].map((_, i) => args.map(a => a[i]))
let [_, foods, colors] = zip(...data).map(uniq)
Reduce the array to two Sets, and then destructure the Sets, and spread each into the respective array:
const data = [["Apple","Fruit","Red"],["Pear","Fruit","Green"],["Orange","Fruit","Orange"],["Carrot","Vegetable","Orange"],["Pea","Vegetable","Green"],["Pumpkin","Vegetable","Orange"]]
const [s1, s2] = data.reduce((acc, arr) => {
acc.forEach((s, i) => s.add(arr[i + 1]))
return acc
}, [new Set(), new Set()])
const Arr1 = [...s1]
const Arr2 = [...s2]
console.log({ Arr1, Arr2 })
You could take a single loop and get the unique values for all items of the nested arrays.
const
getUnique = array => array
.reduce((r, a) => a.map((v, i) => (r[i] || new Set).add(v)), [])
.map(s => [...s]),
data = [["Apple", "Fruit", "Red"], ["Pear", "Fruit", "Green"], ["Orange", "Fruit", "Orange"], ["Carrot", "Vegetable", "Orange"], ["Pea", "Vegetable", "Green"], ["Pumpkin", "Vegetable", "Orange"]],
[, types, colors] = getUnique(data);
console.log(types);
console.log(colors);
Create an object with foods and colors as keys and loop through inserting the appropriate element index each iteration
let data = [
["Apple","Fruit","Red"],
["Pear","Fruit","Green"],
["Orange","Fruit","Orange"],
["Carrot","Vegetable","Orange"],
["Pea","Vegetable","Green"],
["Pumpkin","Vegetable","Orange"]
]
const uniques = {
foods:new Set(),
colors: new Set()
}
data.forEach(a => uniques.foods.add(a[1]) && uniques.colors.add(a[2]) )
// just for demo logs
Object.entries(uniques).forEach(([k,set])=> console.log(k,':', ...set))

How to concatenate previous string of an array with the next one?

I'm having trouble wrapping my head around this, but let's say there an array with these elements:
["apple", "banana", "pear", "kiwi", "orange"]
I would like to transfer this array into:
["apple", "apple/banana", "apple/banana/pear", "apple/banana/pear/kiwi", "apple/banana/pear/kiwi/orange"]
I need this in JavaScript and I'm not sure how to achieve it.
Please note that I'm currently working with ES5.
Here's a simple implementation of what you're trying to do :
ES5
var input = ["apple", "banana", "pear", "kiwi", "orange"];
var prev = '';
var output = input.map(function (el) {
el = prev + el; prev = el + '/'; return el;
});
console.log(output);
ES6
let input = ["apple", "banana", "pear", "kiwi", "orange"];
let prev= '';
let output = input.map( el => { el = prev + el; prev = el+'/'; return el})
console.log(output)
Array.map() is meant for these problems.
The map() method creates a new array with the results of calling a provided function on every element in the calling array.
And while walking through the array with map you can use join() and slice() to concatenate certain values from an original array.
let input = ["apple", "banana", "pear", "kiwi", "orange"];
let output = input.map((el, index) => {
return (input[index-1]) ? input.slice(0, index+1).join('/') : el;
})
output:
Array [
"apple",
"apple/banana",
"apple/banana/pear",
"apple/banana/pear/kiwi",
"apple/banana/pear/kiwi/orange"
]
Some more explanation on what is happening in those 3 lines:
// let's write it out.
let output = input.map((el, index) => {
// If there is a previous index of this array, we need to join it with this one
if (input[index-1]) {
// all previous values including this one
let a = input.slice(0, index+1)
// concatenate them all with a seperator
let b = a.join('/');
return b;
} else {
// if not just return the element
return el;
}
})
You wrote: Please note that I'm currently working with ES5.
Unfortunately, some people do not understand anymore what is ES5 and suggest ES6 solutions (with arrow function expressions, let statements and constants).
Array.map was added to the ECMA-262 standard in the ECMAScript 5.1 edition. It is fully supported by all modern browsers inclusive IE9.
var input = ["apple", "banana", "pear", "kiwi", "orange"],
output = input.map(function(elem, index)
{
return index > 0 ? input.slice(0, index + 1).join('/') : elem;
});
console.log(JSON.stringify(output, null, '\t'));
var fruits = ["apple", "pear", "orange", "banana"];
var i;
for( i=0; i<fruits.length; i++) {
if (i == 0){
continue;
}
var temp = fruits[i];
fruits[i] = fruits[i-1] + "/" + temp;
}
for( i=0; i<fruits.length; i++) {
print(fruits[i]);
}
Here you go!
Points to remember:
Concatenation Operator
For loop
continue statement
Arrays
var array = ["apple", "banana", "pear", "kiwi", "orange"]
var all = [];
var str ="";
for(var i=0;i< array.length;i++)
{
if(array[i-1]){
str += array[i-1]+'/';
all.push(str+array[i])
}
else all.push(array[i])
}
console.log(all);
Time to .reduce it
This works by creating a new array, and accessing the last placed string and appending a '/' and then the next string current.
yourArray.reduce((newArray, current) => newArray.concat(newArray.length > 0 ? newArray[newArray.length - 1] + '/' + current : current), [])
// long version:
yourArray.reduce((newArray, current) => {
if (newArray.length > 0) {
return newArray.concat(current)
} else {
const previousString = newArray[newArray.length - 1]
return newArray.concat(previousString + '/' + current)
}
}, [])
For the ones that do use ES6 or can transpile the code to ES5 (Using i.e: Babel)
const a = ["a", "b", "c", "d", "e"];
const res = a.map((_, i) => a.slice(0, i+1).join("/"));
console.log(res);

create a grouped array using two different arrays

I have below two arrays:
array1 = [{
"type":"test",
"name":"name1"},
{
"type":"dev",
"name":"name2"}]
array2=[{
"type":"test",
"name":"name3"},
{
"type":"dev",
"name":"name4"},
{
"type":"prod",
"name":"name5"}]
I want to group two arrays with "type" and create a new array something like this:
finalArray=[{
"type":"test",
"info":[{
"type":"test",
"name":"name1"}],
[{
"type":"test",
"name":"name3"
}]},
{
"type":"dev",
"info":[{
"type":"dev",
"name":"name2"}],
[{
"type":"dev",
"name":"name4"}]},
{
"type":"prod",
"info":[],
[{
"type":"prod",
"name":"name5"}]
}]
Is there anyway that I can achieve this using javascript, angularjs2, lodash, jquery. I am able to group and create new object as mentioned in using lodash .groupBy. how to add your own keys for grouped output?
But only thing is always I want to push the data from second array in index=1 of "info" and first one to index=0. If any of the array does not have a "type" then the "info" array should have empty/null values.
use _.mapValues to iterate object values with key accessing
var res = _.chain(array1)
.concat(array2)
.groupBy('type')
.mapValues(function(val, key) {
return {
type: key,
info: val
};
})
.values()
.value();
It's possible to achieve the result you want in javascript, or using helper like lodash.
The last part of your question is hard to understand. If an array doesn't have "type", how would you group them. Please provide clearer explanation or modify your expected input and output.
[Updated]
Thanks for your explanation. This is the solution using plain javascript.
// get uniques type from two arrays
const uniqueTypes = new Set(array1
.concat(array2)
.map(x => x.type));
// loop the types, find item in both array
// group it
let result = Array.from(uniqueTypes).reduce((acc, curr) => {
const item1 = array1.find(x => x.type === curr);
const item2 = array2.find(x => x.type === curr);
const info1 = item1 ? [item1] : [];
const info2 = item2 ? [item2] : [];
acc = acc.concat({ type: curr, info: [info1, info2] });
return acc;
}, []);
console.log(result);
jsbin here: https://jsbin.com/mobezogaso/edit?js,console
Here's a working solution :). Hope it helps!
var array1 = [
{
"type":"test",
"name":"name1"
},
{
"type":"dev",
"name":"name2"
}
]
var array2 = [
{
"type":"test",
"name":"name3"
},
{
"type":"dev",
"name":"name4"
},
{
"type":"prod",
"name":"name5"
}
]
var newArray = array1.concat(array2);
var arr1 = [];
var arr2 = [];
var arr3 = [];
var arrTypes = [];
var finalArray = [];
var someArray = [];
for(var i in newArray)
{
if (arrTypes.indexOf(newArray[i].type) === -1){
arrTypes.push(newArray[i].type);
}
if(newArray[i].type === "test"){
arr1.push(newArray[i]);
}
else if(newArray[i].type === "dev"){
arr2.push(newArray[i]);
}
else if(newArray[i].type === "prod"){
arr3.push(newArray[i]);
}
}
someArray.push(arr1);
someArray.push(arr2);
someArray.push(arr3);
for(var j = 0; j < someArray.length; j++){
finalArray.push({
"type": arrTypes[j],
"info": someArray[j]
});
}
console.log(finalArray);
And a short (unreadable?) ES6 solution:
Concat the arrays
Reduce the array into a Map object, with the type as the key
Get the entries iterator - key (type) - value (array of objects)
Use spread to convert the entry iterator to an array
Array#Map the array of entries to the type/info objects
const array1 = [{"type":"test","name":"name1"},{"type":"dev","name":"name2"}];
const array2=[{"type":"test","name":"name3"},{"type":"dev","name":"name4"},{"type":"prod","name":"name5"}];
const result = [...array1.concat(array2).reduce((r, o) => {
r.has(o.type) ? r.get(o.type).push(o) : r.set(o.type, [o]);
return r;
}, new Map).entries()]
.map(([type, info]) => ({
type, info
}));
console.log(result);

How can I return all previous items in a JavaScript array than a current value?

Let's say I have an array:
var myArr = new Array('alpha','beta','gamma','delta');
And that I want a function to return an array of all items before a given item:
function getAllBefore(current) {
var myArr = new Array('alpha','beta','gamma','delta');
var newArr = ???
return newArr;
}
getAllBefore('beta'); // returns Array('alpha');
getAllBefore('delta'); // returns Array('alpha','beta','gamma');
What's the fastest way to get this? Can I split an array on a value? Do I have to loop each one and build a new array on the fly? What do you recommend?
What about if I wanted the opposite, i.e. getAllAfter()?
function getAllBefore(current) {
var myArr = new Array('alpha','beta','gamma','delta');
var i = myArr.indexOf(current);
return i > -1 ? myArr.slice(0, i) : [];
}
Get the index of the specified item. If found, .slice() from 0 to that index. If not found, return an empty array (or whatever other default value you like).
Note that .indexOf() is not supported (for arrays) in IE8 and older, but there is a shim you can use, or you could just use a simple for loop instead.
javascript slice array
// array.slice(start, end)
const FRUITS = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var citrus = FRUITS.slice(1, 3);
// citrus => [ 'Orange', 'Lemon' ]
// Negative values slice in the opposite direction
var fromTheEnd = FRUITS.slice(-3, -1);
// fromTheEnd => [ 'Lemon', 'Apple' ]
array cut only last 5 element
arr.slice(Math.max(arr.length - 5, 0))
Use indexOf and slice:
newArr = myArr.slice(0, myArr.indexOf(current));
Try something like this
var index = myArr.indexOf('beta');
var before = myArray.slice(0, index);
I recently had to do something like this for an array of objects. This is what I went with:
const myArr = [
{ controlId: 1, value: 'alpha'},
{ controlId: 2, value: 'beta' },
{ controlId: 3, value: 'gamma' },
{ controlId: 4, value: 'delta'}
];
function getAllBefore(id) {
const index = myArr.findIndex( ({ controlId }) => controlId === id);
return myArr.filter((_, i) => i < index);
}

Categories