我有一个JSON文件,其中包含一堆歌曲以及相关的歌曲行,诗句编号等。我的目标是打印每个不同的诗句。我在构建有效的循环方面遇到困难。这是JSON文件的示例:
[{ "song": 1, "verse": 1, "lineNum": 1, "line": "Mato Joe Tsinki"},
{ "song": 1, "verse": 1, "lineNum": 2, "line": "Chiti chiti"},
{ "song": 1, "verse": 2, "lineNum": 1, "line": "Raro Raro"},
{ "song": 1, "verse": 2, "lineNum": 2, "line": "Shinan Kibi"},
{ "song": 1, "verse": 2, "lineNum": 3, "line": "Bewa bewa"},
{ "song": 2, "verse": 1, "lineNum": 1, "line": "Ramo Kano"},
{ "song": 2, "verse": 2, "lineNum": 1, "line": "Choro Choro"},
{ "song": 3, "verse": 1, "lineNum": 1, "line": "Pisha Pisha"}]
在此JSON中,共有5节经文。
我写了以下内容,可以成功地打印每首歌的第一节经文,但不能打印后续的经文。
var fs = require('fs');
var colors = require('colors');
fs.readFile('stackoverflow.json', 'utf8', function (err,data) {
data = JSON.parse(data);
for(var i in data) {
var item = data[i];
// construct string song:verse:line
var lineIndex = item.song
lineIndex += ":"+item.verse
lineIndex += ":"+item.lineNum
var numSongs = 20
var songNum = 1
var verseNum = 1
var lineNum = 1
// console.log(verseNum)
while(item.song <= numSongs && item.verse == verseNum)
{
console.log(lineIndex.green + ' ' + item.line);
verseNum++;
}
}
});
已更新以演示控制台日志的期望输出:
歌曲1诗1: “马托·乔辛基” “ Chiti Chiti”
歌曲1诗2: “拉罗罗罗” “ Shinan Kibi” “ Bewa Bewa”
歌曲2诗1: ....
答案 0 :(得分:1)
考虑使用Array.reduce()
,而不是使用while
和for
。
由lines
和line
和lineNum
组成的数组:
var arr = [{ "song": 1, "verse": 1, "lineNum": 1, "line": "Mato Joe Tsinki"}, { "song": 1, "verse": 1, "lineNum": 2, "line": "Chiti chiti"}, { "song": 1, "verse": 2, "lineNum": 1, "line": "Raro Raro"}, { "song": 1, "verse": 2, "lineNum": 2, "line": "Shinan Kibi"}, { "song": 1, "verse": 2, "lineNum": 3, "line": "Bewa bewa"}, { "song": 2, "verse": 1, "lineNum": 1, "line": "Ramo Kano"}, { "song": 2, "verse": 2, "lineNum": 1, "line": "Choro Choro"}, { "song": 3, "verse": 1, "lineNum": 1, "line": "Pisha Pisha"}];
let result = arr.reduce((out, i) => {
let found = out.find(s => s.song === i.song && s.verse === i.verse);
let {line, lineNum, ...newSong} = i;
let {song, verse, ...newLine} = i;
found
? found.lines.push(newLine)
: out.push({...newSong, lines: [newLine]});
return out;
}, []);
console.log(result);
以逗号分隔:
var arr = [{ "song": 1, "verse": 1, "lineNum": 1, "line": "Mato Joe Tsinki"}, { "song": 1, "verse": 1, "lineNum": 2, "line": "Chiti chiti"}, { "song": 1, "verse": 2, "lineNum": 1, "line": "Raro Raro"}, { "song": 1, "verse": 2, "lineNum": 2, "line": "Shinan Kibi"}, { "song": 1, "verse": 2, "lineNum": 3, "line": "Bewa bewa"}, { "song": 2, "verse": 1, "lineNum": 1, "line": "Ramo Kano"}, { "song": 2, "verse": 2, "lineNum": 1, "line": "Choro Choro"}, { "song": 3, "verse": 1, "lineNum": 1, "line": "Pisha Pisha"}];
let result = arr.reduce((out, i) => {
var found = out.find(s => s.song === i.song && s.verse === i.verse);
found
? found.line += ", " + i.line //Song found - combine the lines
: out.push(i); //Song not found - add it as new item
return out;
}, []);
console.log(result);
reduce()
将遍历数组中的每首歌曲以构建一个集合。如果已经在集合中找到相同的歌曲和诗句,则将这些行加在一起。如果没有,它将把整首歌曲添加到收藏中。
也就是说,您尚未明确定义期望输出的样子。
答案 1 :(得分:1)
您可以使用reduce
对诗句进行分组,并使用song
和verse
的{{1}}的每个唯一组合创建一个累加器对象。然后,使用Object.values
获得最终输出。这将为key
和lines
的每个组合创建一个song
数组:
verse
如果您希望var verses =
[{ "song": 1, "verse": 1, "lineNum": 1, "line": "Mato Joe Tsinki"},
{ "song": 1, "verse": 1, "lineNum": 2, "line": "Chiti chiti"},
{ "song": 1, "verse": 2, "lineNum": 1, "line": "Raro Raro"},
{ "song": 1, "verse": 2, "lineNum": 2, "line": "Shinan Kibi"},
{ "song": 1, "verse": 2, "lineNum": 3, "line": "Bewa bewa"},
{ "song": 2, "verse": 1, "lineNum": 1, "line": "Ramo Kano"},
{ "song": 2, "verse": 2, "lineNum": 1, "line": "Choro Choro"},
{ "song": 3, "verse": 1, "lineNum": 1, "line": "Pisha Pisha"}]
const merged = verses.reduce((acc, { song, verse, line }) => {
const key = `${song}-${verse}`
acc[key] = acc[key] || {song, verse, lines: []};
acc[key]["lines"].push(line);
return acc
}, {})
const output = Object.values(merged)
console.log(output)
用lines
分隔,请使用字符串属性并连接每个/
:
line
答案 2 :(得分:0)
这里有另一个版本,该版本使用第一个Array.forEach()将行按song
和verses
进行分组,并注意将它们排在数组的首位(以防原始数组未订购)。然后,我们使用Array.map()获得您的预期输出:
let input = [
{ "song": 1, "verse": 1, "lineNum": 2, "line": "Chiti chiti"},
{ "song": 1, "verse": 1, "lineNum": 1, "line": "Mato Joe Tsinki"},
{ "song": 1, "verse": 2, "lineNum": 1, "line": "Raro Raro"},
{ "song": 1, "verse": 2, "lineNum": 3, "line": "Bewa bewa"},
{ "song": 1, "verse": 2, "lineNum": 2, "line": "Shinan Kibi"},
{ "song": 2, "verse": 1, "lineNum": 1, "line": "Ramo Kano"},
{ "song": 2, "verse": 2, "lineNum": 1, "line": "Choro Choro"},
{ "song": 3, "verse": 1, "lineNum": 1, "line": "Pisha Pisha"}
];
let verses = {};
input.forEach(o =>
{
let k = `${o.song}_${o.verse}`;
verses[k] = verses[k] || {song: o.song, verse: o.verse};
verses[k]["lines"] = verses[k]["lines"] || [];
verses[k]["lines"][o.lineNum] = o.line;
});
let res = Object.values(verses).map(
o => `song ${o.song}, verse ${o.verse}, lines: ${o.lines.filter(Boolean).join(" / ")}`
);
console.log(res);