how to store many arrays to one key - javascript

I just get starting learning JS recently. Now I came across the problem and could not find blogs or tutorial to help very much or I did not get their points!
My problems is how to store many arrays to one key:
My code here:
let lines = fs.readFileSync(inGff).toString().split("\n");
...
let column = lines[i].toString().split("\t");
id = clpP1_69910 or clpP1_54343 or clpP1_69554 ...
obj[id] = column; //only work for one key to one array.
In fact. I can do it simply with Perl:
push #{$obj{$id}}, [#info]
Not sure if there is a similar utility or more advanced in JS. Any suggestions are welcome. Thanks!
enter image description here

You can store arrays inside objects like so:
let data = {};
let keys = ['clpP1_69910', 'clpP1_69915', 'clpP1_69920', 'clpP1_69925'];
// Iterate keys
keys.forEach(el => {
let arr = [];
// Iterate to push array items
for (let i = 0; i < 10; i++) {
arr.push(i);
}
// Assign array to key
data[el] = arr;
// Clear array
arr = null;
});
console.log(data);

Keys can store any type of value
To solve this you should set clpP1_69910 to an empty Array and .push to the array when you add a column.
obj[clpP1_69910] = []
const lines = fs.readFileSync(inGff).toString().split('\n')
const columns = lines.map(line => line.toString().split('\t'))
columns.forEach(column => obj[clpP1_69910].push(column))
Or, the short version:
obj[clpP1_69910] = fs.readFileSync(inGff).toString().split('\n').map(line => line.toString().split('\t')).reduce((acc, cur) => acc.concat(cur), [])
The last part, the .reduce section, flattens the array of arrays, returning all the columns.

Related

Duplicating array in nested array with one value change, changes entire nested array in javascript

I have an nested array. Example
let array = [['a','e1'],['b','b1']]
What i want to achive is a new nested array with a copy of one of the array's and a change to that copy.
when i run it though a loop (tried for and foreach) it duplicates the change throughout the entire nested array.
here is an example of the code (note its not key: index and just an example. the actual inside array contains 11 values in total)
let array = [['a','e1'],['b','b1']]
let result = []
for(let x of array){
result.push(x);
if(x[1]==='e1'){
let newRow = x;
newRow[1] = 'e2'
result.push(newRow);
}
}
//result: [[a,e2],[a,e2],[b,b1]]
let needResult = [['a','e1'],['a','e2'],['b','b1']]
Any assistance in this would be greatly appreciated.
Working example of the script : https://stackblitz.com/edit/js-ah1bvf?file=index.js
Thanks
Instead of use let newRow = x;, as #tadman said in the comment you need to use another way like create a new array let newRow = []; //for example
let array = [['a','e1'],['b','b1'], ['c', 'e1']]
let result = []
for(let x of array){
result.push(x);
if(x[1]==='e1'){
const newRow = [];
newRow[0] = x[0];
newRow[1] = 'e2'
result.push(newRow);
}
}
console.log(result)
As #tadman said in the comment :
let newRow = [...x] // works.
I did not select #simons answer though valid as stated in my question the array can be quite large and I don't necessarily know exactly how long it is.
Thanks for the help!

Nodejs find multiple value

I have two lists:
lista_source: 'B10L-A2,AABan38711$B10L-A2,AABan38811$B12A-A,AABan38912$B14-A2,AABan39314$B16B-A,AABan39616$B12A-A,AABan39818$B16L-B,AABan39919$B16L-B,AABan40019$B12A-A,AABan41112'
second_list: 'B10L-A2,B12A-A,B16L-B'
As a result I would like to get the following list (or similar one):
result = [B10L-A2:AABan38711,AABan38811],[B12A-A:AABan38912,AABan41112,AABan39818],[B16L-B:AABan39919,AABan40019]
In short, I'm looking for multiple values for the 2nd lists items.
I tried the filter function and write it to csv file but does not really work.
const first_list_object= first_list.split('$');
const second_list_object= second_list.split(',');
for (let i = 0; i < second_list_object.length; i++) {
let results= first_list_object.filter(x => x.includes(second_list_object[i]));
console.log(results);
writer = csvWriter({ sendHeaders: false });
writer.pipe(fs.createWriteStream(__dirname + '/lista.csv', { flags: 'a' }));
writer.write({
results
});
}
How should I solve it? Is there any better solution than filter?
A javascript object as output. If you need, I can convert this to .csv too.
const lista_source = 'B10L-A2,AABan38711$B10L-A2,AABan38811$B12A-A,AABan38912$B14-A2,AABan39314$B16B-A,AABan39616$B12A-A,AABan39818$B16L-B,AABan39919$B16L-B,AABan40019$B12A-A,AABan41112'
const second_list = 'B10L-A2,B12A-A,B16L-B'
// convert data to arrays
const source = lista_source.split(",")
const second = second_list.split(",")
// filter out source list items (into seperate object value) for each second list item
const res = second.reduce((obj, sec_key) => {
// get item, if string is not exact key name and string includes key name
const filtered = source.filter(key => key !== sec_key && key.includes(sec_key))
return ({...obj, [sec_key]: filtered })
}, {})
console.log(res)
Assuming that structure of the strings are gonna be like in question, I wrote same basic regex to split on and then add them accordingly to object. See if that's what you want.
Edit:
After rereading your question, I realized that comma actually doesn't separate values in your string but dolar sign instead (kinda weird but ok). I also added an if to take only values present in second list.
const lista_source = 'B10L-A2,AABan38711$B10L-A2,AABan38811$B12A-A,AABan38912$B14-A2,AABan39314$B16B-A,AABan39616$B12A-A,AABan39818$B16L-B,AABan39919$B16L-B,AABan40019$B12A-A,AABan41112'
const second_list = 'B10L-A2,B12A-A,B16L-B'.split(',')
const array = lista_source.match(/B[0-9]{2}[A-Z]-[A-Z][0-9]?,[A-Za-z0-9_]{10}/g)
let result = {}
for (let value of array) {
let [key, s] = value.split(',')
// only take keys form contained in second list
if(!second_list.includes(key)){
continue
}
key in result ? result[key] = [s, ...result[key]] : result[key] = [s]
}
console.log(result)

More condense way to combine same elements in array to one string in array?

I'm trying to learn how to refactor my code, and I have written the following function block:
joinSame = (arr) =>{
let simplifiedArr = [];
for(let i=0; i < arr.length; i++){
const tempLast = arr.lastIndexOf(arr[i]);
const element = arr[i].toString()
if(i === tempLast){
simplifiedArr.push(element);
} else {
const tempMultiplier = tempLast-i+1;
simplifiedArr.push(element.repeat(tempMultiplier));
i = tempLast;
}
}
return simplifiedArr;
}
The idea is that if I input a sorted array ([3,3,3,4,'a','a']), I want the output to be an array with similar entities combined into a string (['333', '4', 'aa']). I tried to use the .map and .forEach array method, but my problem is trying to "hop" the index to go to the next unique element.
Am I overcomplicating things by trying to get it to refactor to a .map or .forEach method, or is my code "good" enough to let it go?
You can make use of reduce and then take Object.values:
const arr = [3,3,3,4,'a','a'];
const result = Object.values(arr.reduce((a,b)=>(a[b]=(a[b] || '')+b,a),{}))
console.log(result);

Jquery check if one array contains same value

I have an simple javascript array that may contain duplicates or maynot contain duplicates.
var names = [
['aaa','pin/test1.html'],
['bbb','pin/test2.html'],
['ttt','test.html'],
['ggg','test.html'],
['yyy','un/777.html'],
['ggg','test3.html'],
['nnn','test3.html'],
['eee','n/777.html'],
['sss','pin/test1.html'],
['xxx','pin/test2.html'],
['ppp','pin/test1.html'],
];
I need to find the duplicate filepath and put their name into new array. If there is no duplicate then assign its name in first and then assign '' after two values. I could point all the codes that I have tried but it doesnt work. I accept jquery solution also. The expected outcome is this.
var outcome = [
[['aaa','sss','ppp'], 'pin/test1.html'],
[['bbb','eee','xxx'], 'pin/test2.html'],
[['ttt','ggg',''], 'test.html'],
[['yyy','',''], 'un/777.html'],
[['ggg','nnn',''], 'test3.html'],
];
What I have tried is this
for (var i = 0; i < arr.length; i++) {
var uniqueNames = [];
$.each(arr[i], function (i, el) {
if ($.inArray(el, uniqueNames) === -1) uniqueNames.push(el);
});
console.log(uniqueNames);
}
You could take a hash table and an array of empty strings and find the next slot for the value.
The array is reduced by taking an object as accumulator and a destructure array as value (the first part of the array) and key (the second part, aka filepath).
Inside of Array#reduce, a property check with the key is made and if undefined, an array with the wanted structure (array with two items, the first is an array with three emty spaces and the key) is being assigned by using a logical nullish assignment ??=.
The next line assigns the value to the next free slot, an item with an empty string.
Finally the accumulator is returned.
To get only an array as result, a conversion of the values of the object takes place.
let names = [['aaa','pin/test1.html'], ['bbb','pin/test2.html'], ['ttt','test.html'], ['ggg','test.html'], ['yyy','un/777.html'], ['ggg','test3.html'], ['nnn','test3.html'], ['eee','n/777.html'], ['sss','pin/test1.html'], ['xxx','pin/test2.html'], ['ppp','pin/test1.html']],
grouped = Object.values(names.reduce((r, [v, k]) => {
r[k] ??= [Array(3).fill(''), k];
r[k][0][r[k][0].indexOf('')] = v;
return r;
}, {}));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
const aux = (names) => {
const hash = {};
let max = 0;
names.forEach(ele => {
if (!hash[ele[1]]) hash[ele[1]] = [];
hash[ele[1]].push(ele[0]);
max = Math.max(hash[ele[1]].length, max);
});
return Object.keys(hash).map(ele => [[...hash[ele], ...Array(max -hash[ele].length).fill("")], ele]);
}
var names = [
['aaa','pin/test1.html'],
['bbb','pin/test2.html'],
['ttt','test.html'],
['ggg','test.html'],
['yyy','un/777.html'],
['ggg','test3.html'],
['nnn','test3.html'],
['eee','n/777.html'],
['sss','pin/test1.html'],
['xxx','pin/test2.html'],
['ppp','pin/test1.html'],
];
console.log(aux(names))
This might help
You do not need jQuery for dealing with regular JS structure, you can achieve what you want with a simple code like this:
var names = [['aaa','pin/test1.html'],['bbb','pin/test2.html'],['ttt','test.html'],['ggg','test.html'],['yyy','un/777.html'],['ggg','test3.html'],['nnn','test3.html'],['eee','n/777.html'],['sss','pin/test1.html'],['xxx','pin/test2.html'],['ppp','pin/test1.html'],];
let lengthToFill = 0;
// collecting all the duplicates into a map
const pathMap = {};
names.forEach(name => {
// just in case if you're not familiar with array destructuring
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
const [pathName, path] = name;
// make sure we have an array to deal with
// just in case you're not familiar with Nullish coalescing operator (??)
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator
pathMap[path] = pathMap[path] ?? [];
pathMap[path].push(pathName);
// tracking the max number of elements we're adding into a single entry
lengthToFill = Math.max(lengthToFill, pathMap[path].length);
});
const result = Object.entries(pathMap).map(entry => {
// constructing new array entry based on the data we've collected so far
return [
entry[1].concat(Array(lengthToFill - entry[1].length).fill('')),
entry[0],
];
});
console.log(result);
This solution will work for any number of elements that you'd like to fill the array with ''. It makes sure that the length of final listing is the same for all entries.

Simplest vanilla JavaScript way to pair items from a unidimensional array into a multidimensional array?

Currently I have a unidimensional array, e.g. ['thing1', 'cond1', 'thing2', 'cond2', 'thing3']
I would like to pair each item to create a new multidimensional array like so [['thing1', 'cond1'], ['thing2', 'cond2'], ['thing3']]. I don't mind the last item being ['thing3', undefined] – if anything this is preferable unless someone raises this as bad practice.
So far I have
const pair = (arr) => {
let paired = [];
for (i = 0; i < arr.length; i += 2) {
paired.push([arr[i], arr[i+1]]);
}
return paired;
}
You can try this out in my JS Bin example.
This works perfectly fine AFAIA but I'd love this to be as concise as possible using modern JS and I'm not as polished as I should be with my array manipulation.
Thanks in advance to everyone who gives this a go.
Let the challenge... BEGIN!
You could take a while loop with an index variable. For pushing a pair take slice.
const pair = array => {
let paired = [],
i = 0;
while (i < array.length) paired.push(array.slice(i, i += 2));
return paired;
}
var array = ['thing1', 'cond1', 'thing2', 'cond2', 'thing3'],
paired = pair(array);
console.log(paired);
You can try this regex. Group the values by finding the number by using regular expression.
const data = ['thing1', 'cond1', 'thing2', 'cond2', 'thing3'];
const result = {};
data.forEach(value => {
const index = value.replace(/[^\d.]/g, '');
if (typeof result[index] == 'undefined') {
result[index] = [];
}
result[index].push(value);
});
const array = Object.values(result);
console.log(array);

Categories