Reputation: 162
I'm making a small tool for handling translations for a website. I already got this code working, but I feel there should be some more elegant and readable way using array methods (mine looks like a mess...).
Basically, I'll get input in the format shown in code (data_import, this is just fake data for testing). It has 4 columns [translationTag, uniqueId, languageId, translation]. Order of rows is same for every language and there is same number of rows for each language. Number of languages may change from 2 upwards.
the desired output would be like this:
const data_import = [
['aaa', {id:1, langId:1, finnish:'tuntematon'}, {id:5, langId:4, english:'unknown'}, {id:9, langId:6, swedish:'okänd'}],
['bbb', {id:2, langId:1, finnish:'auto'}, {id:6, langId:4, english:'car'}, {id:10, langId:6, swedish:'bil'}],
['ccc', {id:3, langId:1, finnish:'polkupyörä'}, {id:7, langId:4, english:'bicycle'}, {id:11, langId:6, swedish:'cykel'}],
['ddd', {id:4, langId:1, finnish:'rullalauta'}, , {id:8, langId:4, english:'skateboard'}, {id:12, langId:6, swedish:'skateboard'}]
];
Here is my code that 'works' but is ugly and unreadable...
export const language = ['Finnish', 'Estonia', 'Polish', 'English', 'Spanish', 'Swedish'];
const data_import = [
['aaa', 1, 1, 'tuntematon'],
['bbb', 2, 1, 'auto'],
['ccc', 3, 1, 'polkupyörä'],
['ddd', 4, 1, 'rullalauta'],
['aaa', 5, 4, 'unknown'],
['bbb', 6, 4, 'car'],
['ccc', 7, 4, 'bicycle'],
['ddd', 8, 4, 'skateboard'],
['aaa', 9, 6, 'okänd'],
['bbb', 10, 6, 'bil'],
['ccc', 11, 6, 'cykel'],
['ddd', 12, 6, 'skateboard']];
export const data = process_test(data_import);
function process_test(data) {
const numberOfCols = data[0].length;
const idIndex = numberOfCols - 2;
const arr_result = []
let rowMax = 0;
let rowMaxMulti = 0;
let langIdLast = 0;
data.forEach((row, index) => {
// if = add non-language cols and first language column
if(row[idIndex] === data[0][idIndex]) {
rowMax = index + 1;
const transItem = row.slice(0, idIndex-1);
transItem.push({ id:row[idIndex], langId:row[idIndex], [language[row[idIndex] - 1]]:row[idIndex + 1] });
arr_result[index] = transItem;
langIdLast = row[idIndex];
}
// add other languages to datarow
else {
const transItem = { id:row[idIndex - 1], langId:row[idIndex], [language[row[idIndex] + 1]]:row[idIndex + 1] };
if(langIdLast !== row[idIndex]) rowMaxMulti++;
arr_result[index - rowMax * rowMaxMulti].push(transItem);
langIdLast = row[idIndex];
}
})
return(arr_result);
}
Upvotes: 3
Views: 65
Reputation: 1712
You can group the data by tag
with Array.prototype.reduce
and map it out to the desired format with Object.keys
const language = ['Finnish', 'Estonia', 'Polish', 'English', 'Spanish', 'Swedish'];
const data_import = [['aaa', 1, 1, 'tuntematon'],['bbb', 2, 1, 'auto'],['ccc', 3, 1, 'polkupyörä'],['ddd', 4, 1, 'rullalauta'],['aaa', 5, 4, 'unknown'],['bbb', 6, 4, 'car'],['ccc', 7, 4, 'bicycle'],['ddd', 8, 4, 'skateboard'],['aaa', 9, 6, 'okänd'],['bbb', 10, 6, 'bil'],['ccc', 11, 6, 'cykel'],['ddd', 12, 6, 'skateboard']];
const grouped = data_import.reduce((all, [tag, id, langId, tran]) => {
if (!all.hasOwnProperty(tag)) all[tag] = [];
all[tag].push({id, langId, [language[langId-1]]: tran});
return all;
}, {});
const result = Object.keys(grouped).map(tag => [tag, ...grouped[tag]]);
console.log(result);
Upvotes: 1
Reputation: 10262
You could also use
const data_import = [["aaa",1,1,"tuntematon"],["aaa",5,4,"unknown"],["aaa",9,6,"okänd"],["bbb",6,4,"car"],["bbb",2,1,"auto"],["bbb",10,6,"bil"],["ccc",11,6,"cykel"],["ccc",7,4,"bicycle"],["ccc",3,1,"polkupyörä"],["ddd",8,4,"skateboard"],["ddd",4,1,"rullalauta"],["ddd",12,6,"skateboard"]],
language = ['Finnish', 'Estonia', 'Polish', 'English', 'Spanish', 'Swedish'];
const keys =[...new Set(data_import.map(v => v[0]))];
let result = keys.map(key => [key, data_import.filter(v => v[0] == key).map(v => {
return {
id: v[1],
langId: v[2],
[language[v[2]-1]]: v[3]
}
})]);
console.log(result)
.as-console-wrapper {max-height: 100% !important;top: 0;}
Upvotes: 0
Reputation: 371019
It would be simpler to reduce
into an object indexed by the translation tag, and then get that object's values. On each iteration, create an array for the translation tag if it doesn't already exist in the accumulator. Identify the language name from the langId
of the current item, and push
the new object to the array:
const language = ['Finnish', 'Estonia', 'Polish', 'English', 'Spanish', 'Swedish'];
const data_import = [
['aaa', 1, 1, 'tuntematon'],
['bbb', 2, 1, 'auto'],
['ccc', 3, 1, 'polkupyörä'],
['ddd', 4, 1, 'rullalauta'],
['aaa', 5, 4, 'unknown'],
['bbb', 6, 4, 'car'],
['ccc', 7, 4, 'bicycle'],
['ddd', 8, 4, 'skateboard'],
['aaa', 9, 6, 'okänd'],
['bbb', 10, 6, 'bil'],
['ccc', 11, 6, 'cykel'],
['ddd', 12, 6, 'skateboard']];
const data = Object.values(data_import.reduce((a, [tTag, id, langId, word]) => {
if (!a[tTag]) a[tTag] = [tTag];
const langName = language[langId - 1];
a[tTag].push({ id, langId, [langName]: word });
return a;
}, {}));
console.log(data);
Upvotes: 2