Split nested array into multiple arrays - javascript

I have a string that looks like this:
str = {1|2|3|4|5}{a|b|c|d|e}
I want to split it into multiple arrays. One containing all the first elements in each {}, one containing the second element, etc. Like this:
arr_0 = [1,a]
arr_1 = [2,b]
arr_2 = [3,c]
.....
The best I can come up with is:
var str_array = str.split(/}{/);
for(var i = 0; i < str_array.length; i++){
var str_row = str_array[i];
var str_row_array = str_row.split('|');
arr_0.push(str_row_array[0]);
arr_1.push(str_row_array[1]);
arr_2.push(str_row_array[2]);
arr_3.push(str_row_array[3]);
arr_4.push(str_row_array[4]);
}
Is there a better way to accomplish this?

Try the following:
var zip = function(xs, ys) {
var out = []
for (var i = 0; i < xs.length; i++) {
out[i] = [xs[i], ys[i]]
}
return out
}
var res = str
.split(/\{|\}/) // ['', '1|2|3|4|5', '', 'a|b|c|d|e', '']
.filter(Boolean) // ['1|2|3|4|5', 'a|b|c|d|e']
.map(function(x){return x.split('|')}) // [['1','2','3','4','5'], ['a','b','c','d','e']]
.reduce(zip)
/*^
[['1','a'],
['2','b'],
['3','c'],
['4','d'],
['5','e']]
*/

Solution
var str = '{1|2|3|4|5}{a|b|c|d|e}'.match(/[^{}]+/g).map(function(a) {
return a.match(/[^|]+/g);
}),
i,
result = {};
for (i = 0; i < str[0].length; i += 1) {
result["arr_" + i] = [+str[0][i], str[1][i]];
}
How it works
The first part, takes the string, and splits it into the two halves. The map will return an array after splitting them after the |. So str is left equal to:
[
[1,2,3,4,5],
['a', 'b', 'c', 'd', 'e']
]
The for loop will iterate over the [1,2,3,4,5] array and make the array with the appropriate values. The array's are stored in a object. The object we are using is called result. If you don't wish for it to be kept in result, read Other
Other
Because you can't make variable names from another variable, feel free to change result to window or maybe even this (I don't know if that'll work) You can also make this an array
Alternate
var str = '{1|2|3|4|5}{a|b|c|d|e}'.match(/[^{}]+/g).map(function(a) { return a.match(/[^|]+/g); }),
result = [];
for (var i = 0; i < str[0].length; i += 1) {
result[i] = [+str[0][i], str[1][i]];
}
This is very similar except will generate an Array containing arrays like the other answers,

Related

how can i make my function handle multiple string arrays?

i've been working for some homework in replicating a json parse like function and currently i wrote a function as follows :
var arr = '[a, [a, bjng], n]'
var intoArray = function(string) {
if (string.length <= 2) {
return [];
}
var resultsArr = [];
var toJoin = [];
var simpArr = string.slice(1, string.length - 1).replace(/['"]+/g, '').replace(/[' '']+/g, '').split(',');
for (var a = 0; a < simpArr.length; a++) {
if (simpArr[a].includes('[')) {
while (!simpArr[a].includes(']')) {
toJoin.push(simpArr[a]);
a++;
}
}
if (simpArr[a].includes(']')) {
toJoin.push(simpArr[a]);
}
}
var joined = toJoin.join(',')
var joint = joined.slice(1, joined.length - 1).replace(/['"]+/g, '').replace(/[' '']+/g, '').split(',')
for (var a = 0; a < simpArr.length; a++) {
if (!toJoin.includes(simpArr[a])) {
resultsArr.push(simpArr[a])
}
if (simpArr[a] === toJoin[0]) {
resultsArr[a] = joint
}
}
return resultsArr
};
console.log(intoArray(arr))
when run it converts this string '[a, [a, bjng], n]'(this is all just one big string) into [ 'a', [ 'a', 'bjng' ], 'n' ] (this is an array with multiple string and another array inside, this is the desired behavior). However when the sample string has more than one array inside of it like '[a, [a, bjng],[c] , n]' the result is that it is taken as just one bigger array like [ 'a', [ 'a', 'bjng]', '[c' ], 'n' ] (notice how instead of creating two array it thinks that '[a' trough 'c]' is one big array), i'm still learning so some insight would be much appreciated or if someone has some idea of how i can adapt it to handle multiple arrays!!! or perhaps a better implemntation?
Logic is identical to that of my last answer to your similar question here, except it uses chunks of consecutive characters instead of individual characters in order to handle strings longer than 1.
const string = '[a, [a, bjng], n]'.slice(1, -1);
const chunks = string.match(/\w+|[\[\]|,| ]/g);
const array = [];
let currArr = array;
for (const chunk of chunks) {
/\w/.test(chunk) && currArr.push(chunk);
chunk == ']' && (currArr = array);
if (chunk == '[') {
currArr = [];
array.push(currArr);
}
}
console.log(array); // [ 'a', [ 'a', 'bjng' ], 'n' ]
#GirkovArpa made a good start, but as #Barmar already mentioned: you will need some kind of recursion if you want to process arbitrary (deeper) array structures correctly. Here is my (rudimentary) take on it:
const string = '[a, [ [d,e,[f,g]], bjng], [c], n]';
function parse(str){
function add2arr(a,p){ var c
do c=p.shift()
while( c && (/\w/.test(c)&&a.push(c)
|| c==','
|| c=='[' &&a.push(add2arr([],p))) );
return a
}
const parts = str.replace(/\s*/g,"").match(/\w+|[\[\],]/g);
if(parts.shift()=='[') return add2arr([],parts);
}
console.log(parse(string))
// or, much simpler: use JSON.parse:
console.log(JSON.parse(string.replace(/(\w+)/g,'"$1"')));

Create nested Javascript Object dynamically

I have got a . (dot) separated string, from which I want to create nested JSON object. The length of the string is not fixed. For example,
var string = 'a.b.c.d';
Then my JSON object should be as following:
a: {
b: {
c:{
d: {
//Some properties here.
}
}
}
}
I've tried following code:
var packageName = "a.b.c.d"
var splitted = packageName.split('.');
var json = {};
for(var i=0;i<splitted.length-1;i++){
json[splitted[i]] = splitted[i+1];
}
But this returns
{
a: 'b',
b: 'c',
c: 'd'
}
But this is not what I want. I've also searched on google and found similar questions, but no solutions answer my problem. For example this.
A good use case for reduce
packageName = "a.b.c.d";
initProps = {hi: 'there'};
obj = packageName.split('.').reduceRight((o, x) => ({[x]: o}), initProps);
console.log(JSON.stringify(obj))
If you find loops easier to work with, a loop could be written concisely as
result = {};
ptr = result;
for (let prop of packageName.split('.'))
ptr = ptr[prop] = {};
You need to create a new object each time and attribute it to the last object created. And it goes until splitted.length, not splitted.length - 1, because you're using <, not <=.
var packageName = "a.b.c.d";
var splitted = packageName.split('.');
var json = {};
var current = json;
for (var i = 0; i < splitted.length; i++) {
current[splitted[i]] = {};
current = current[splitted[i]];
}
console.log(json);
You may use the last splittted part as property for some payload.
I suggest to keep the object reference and use a temporary variable for aceessing an creating a new property, if necessary.
Please avoid the use of JSON for not stringified objects.
var packageName = "a.b.c.d",
splitted = packageName.split('.'),
result = {},
temp = result,
i;
for (i = 0; i < splitted.length - 1; i++) {
temp[splitted[i]] = temp[splitted[i]] || {};
temp = temp[splitted[i]];
}
temp[splitted[i]] = { some: 'data' };
console.log(result);

Algorithm to sort an array in JS

I have an array
var arr= [
["PROPRI","PORVEC"],
["AJATRN","PROPRI"],
["BASMON","CALVI"],
["GHICIA","FOLELI"],
["FOLELI","BASMON"],
["PORVEC","GHICIA"]
] ;
And I'm trying to sort the array by making the second element equal to the first element of the next, like below:
arr = [
["AJATRN","PROPRI"],
["PROPRI","PORVEC"],
["PORVEC","GHICIA"],
["GHICIA","FOLELI"],
["FOLELI","BASMON"],
["BASMON","CALVI"]
]
The context is : these are somes sites with coordinates, I want to identify the order passed,
For exemple, I have [A,B] [C,D] [B,C] then I know the path is A B C D
I finally have one solution
var rs =[];
rs[0]=arr[0];
var hasAdded=false;
for (var i = 1; i < arr.length; i++) {
hasAdded=false;
console.log("i",i);
for (var j = 0, len=rs.length; j < len; j++) {
console.log("j",j);
console.log("len",len);
if(arr[i][1]===rs[j][0]){
rs.splice(j,0,arr[i]);
hasAdded=true;
console.log("hasAdded",hasAdded);
}
if(arr[i][0]===rs[j][1]){
rs.splice(j+1,0,arr[i]);
hasAdded=true;
console.log("hasAdded",hasAdded);
}
}
if(hasAdded===false) {
arr.push(arr[i]);
console.log("ARR length",arr.length);
}
}
But it's not perfect, when it's a circle like [A,B] [B,C] [C,D] [D,A]
I can't get the except answer
So I really hope this is what you like to achieve so have a look at this simple js code:
var vector = [
["PROPRI,PORVEC"],
["AJATRN,PROPRI"],
["BASMON,CALVI"],
["GHICIA,FOLELI"],
["FOLELI,BASMON"],
["PORVEC,GHICIA"]
]
function sort(vector) {
var result = []
for (var i = 1; i < vector.length; i++) result.push(vector[i])
result.push(vector[0])
return (result)
}
var res = sort(vector)
console.log(res)
Note: Of course this result could be easily achieved using map but because of your question I'm quite sure this will just confuse you. So have a look at the code done with a for loop :)
You can create an object lookup based on the first value of your array. Using this lookup, you can get the first key and then start adding value to your result. Once you add a value in the array, remove the value corresponding to that key, if the key has no element in its array delete its key. Continue this process as long as you have keys in your object lookup.
var vector = [["PROPRI", "PORVEC"],["AJATRN", "PROPRI"],["BASMON", "CALVI"],["GHICIA", "FOLELI"],["FOLELI", "BASMON"],["PORVEC", "GHICIA"]],
lookup = vector.reduce((r,a) => {
r[a[0]] = r[a[0]] || [];
r[a[0]].push(a);
return r;
}, {});
var current = Object.keys(lookup).sort()[0];
var sorted = [];
while(Object.keys(lookup).length > 0) {
if(lookup[current] && lookup[current].length) {
var first = lookup[current].shift();
sorted.push(first);
current = first[1];
} else {
delete lookup[current];
current = Object.keys(lookup).sort()[0];
}
}
console.log(sorted);

How to separate array of comma separated string into various arrays?

What's the best way to convert this array of comma separated values
[ 'com--test,LFutx9mQbTTyRo4A9Re5ksjdnfsI4cKN4q2,on',
'com--fxtrimester,SEzlksdfMpW3FxkSbzL7eo5MmqkPczCl2,on',
'com--fxtrimester,LFutx9mQbTTyRoldksfns4A9Re5I4cKN4q2,on' ]
Into three arrays?
[ 'com--test', [ LFutx9mQbTTyRo4A9Re5Ilsdf4cKN4q2', ['on',
'com--fxtrimester', SEzMpW3FxkSbzL7eo5MmlkdfqkPczCl2', 'on',
'com--fxtrimester' ] LFutksdfx9mQbTTyRo4A9Re5I4cKN4q2 ] 'on']
I was trying something like:
var indexToSplit = unique.indexOf(',');
var status = unique.slice(3, indexToSplit - 1);
var use = unique.slice(2, indexToSplit - 2);
var pros = unique.slice(0, indexToSplit - 3);
console.log(pros);
But I figured that is wrong ... any help is appreciated!
You will have to loop over array and use string.split to get seperate parts.
Once you have seperate parts, you can push them to necessary array;
var d = [ 'com--test,LFutx9mQbTTyRo4A9Re5ksjdnfsI4cKN4q2,on',
'com--fxtrimester,SEzlksdfMpW3FxkSbzL7eo5MmqkPczCl2,on',
'com--fxtrimester,LFutx9mQbTTyRoldksfns4A9Re5I4cKN4q2,on'];
var result = [[],[],[]];
var len = 3;
d.forEach(function(str, i){
var _tmp = str.split(',');
for (var i = 0; i<len; i++){
result[i].push(_tmp[i])
}
})
console.log(result)
A little generic way.
Loop over data and split each string using comma(,)
Loop over split values and check if necessary array exists.
If not, initialise array, but you cannot do p[i] = [] as this will push to first value. You will have to also initialise all previous values. For this, you can use new Array(length). By default, if length is greater than 0, all indexes will be initialise to undefined.
Now push to necessary array. Position will be maintained.
var d = ['com--test,LFutx9mQbTTyRo4A9Re5ksjdnfsI4cKN4q2,on',
'com--fxtrimester,SEzlksdfMpW3FxkSbzL7eo5MmqkPczCl2,on',
'com--fxtrimester,LFutx9mQbTTyRoldksfns4A9Re5I4cKN4q2,on,test'
];
var result = d.reduce(function(p, c, index) {
var _tmp = c.split(',');
for (var i = 0; i < _tmp.length; i++) {
// Check if position not defined.
if (p[i] === undefined)
// Initialize array and add default (undefined) to all elements before current element
p[i] = new Array(index);
p[i].push(_tmp[i])
}
return p;
}, [])
console.log(result)
With map this becomes:
for positions X out of 0, 1 and 2:
convert each item in the list into an array, and choose the Xth item
var start = [ 'com--test,LFutx9mQbTTyRo4A9Re5ksjdnfsI4cKN4q2,on',
'com--fxtrimester,SEzlksdfMpW3FxkSbzL7eo5MmqkPczCl2,on',
'com--fxtrimester,LFutx9mQbTTyRoldksfns4A9Re5I4cKN4q2,on' ]
var out = [0,1,2].map(i =>
start.map(x => x.split(',')[i]) )
console.log(out)
Since your question does not ask for a more general case, i am safely assuming it for 3 array. We can use forEach function on array below code can be one amongst the possible solutions
var arr1 = [];
var arr2 = [];
var arr3 = [];
var x = ['com--test,LFutx9mQbTTyRo4A9Re5ksjdnfsI4cKN4q2,on', 'com--fxtrimester,SEzlksdfMpW3FxkSbzL7eo5MmqkPczCl2,on', 'com--fxtrimester,LFutx9mQbTTyRoldksfns4A9Re5I4cKN4q2,on']
x.forEach(function(data) {
var dataArray = data.split(',');
arr1.push(dataArray[0]);
arr2.push(dataArray[1]);
arr3.push(dataArray[2]);
});
console.log(arr1)
console.log(arr2)
console.log(arr3)

Sort array by order according to another array

I have an object that is being returned from a database like this: [{id:1},{id:2},{id:3}]. I have another array which specified the order the first array should be sorted in, like this: [2,3,1].
I'm looking for a method or algorithm that can take in these two arrays and return [{id:2},{id:3},{id:1}]. Ideally it should be sort of efficient and not n squared.
If you want linear time, first build a hashtable from the first array and then pick items in order by looping the second one:
data = [{id:5},{id:2},{id:9}]
order = [9,5,2]
hash = {}
data.forEach(function(x) { hash[x.id] = x })
sorted = order.map(function(x) { return hash[x] })
document.write(JSON.stringify(sorted))
function sortArrayByOrderArray(arr, orderArray) {
return arr.sort(function(e1, e2) {
return orderArray.indexOf(e1.id) - orderArray.indexOf(e2.id);
});
}
console.log(sortArrayByOrderArray([{id:1},{id:2},{id:3}], [2,3,1]));
In your example, the objects are initially sorted by id, which makes the task pretty easy. But if this is not true in general, you can still sort the objects in linear time according to your array of id values.
The idea is to first make an index that maps each id value to its position, and then to insert each object in the desired position by looking up its id value in the index. This requires iterating over two arrays of length n, resulting in an overall runtime of O(n), or linear time. There is no asymptotically faster runtime because it takes linear time just to read the input array.
function objectsSortedBy(objects, keyName, sortedKeys) {
var n = objects.length,
index = new Array(n);
for (var i = 0; i < n; ++i) { // Get the position of each sorted key.
index[sortedKeys[i]] = i;
}
var sorted = new Array(n);
for (var i = 0; i < n; ++i) { // Look up each object key in the index.
sorted[index[objects[i][keyName]]] = objects[i];
}
return sorted;
}
var objects = [{id: 'Tweety', animal: 'bird'},
{id: 'Mickey', animal: 'mouse'},
{id: 'Sylvester', animal: 'cat'}],
sortedIds = ['Tweety', 'Mickey', 'Sylvester'];
var sortedObjects = objectsSortedBy(objects, 'id', sortedIds);
// Check the result.
for (var i = 0; i < sortedObjects.length; ++i) {
document.write('id: '+sortedObjects[i].id+', animal: '+sortedObjects[i].animal+'<br />');
}
To my understanding, sorting is not necessary; at least in your example, the desired resulting array can be generated in linear time as follows.
var Result;
for ( var i = 0; i < Input.length; i++ )
{
Result[i] = Input[Order[i]-1];
}
Here Result is the desired output, Input is your first array and Order the array containing the desired positions.
var objArray = [{id:1},{id:2},{id:3}];
var sortOrder = [2,3,1];
var newObjArray = [];
for (i in sortOrder) {
newObjArray.push(objArray[(sortOrder[i]) - 1])
};
Why not just create new array and push the value from second array in?? Correct me if i wrong
array1 = [];
array2 = [2,3,1];
for ( var i = 0; i < array2 .length; i++ )
{
array1.push({
id : array2[i]
})
}

Categories