问题描述
我已经研究了几天,遗憾的是我无法找到正确的搜索字词或我缺乏技能的正确答案。
我正在将 ListServ 转换为 discourse。我正在将 RSS 提要转换为 JSON。 源数据示例:
{
"title": "tech: 18F presentation","id": 2,"body": "Sadly,my biggest concern is whether it will run on Linux or Windows. And I guess if they’ll thrown even more java at it.","date": "Fri,28 May 2021 20:50:04 +0000","author": "john_doe"
},{
"title": "Re: tech: 18F presentation","id": 3,"body": "throw more java,indeed. What a moon shot.","author": "john_doe2"
},"id": 4,"body": "Please stop saying moonshot,its not dodgecoin","author": "jane_doe"
},
我的数据结构需要如下所示:
{
"topics": [
{
"id": 1,"title": "tech: 18F presentation","pinned": false,"posts": [
{
"title": "Re: tech: 18F presentation","author": "john_doe2"
},{
"title": "Re: tech: 18F presentation",]
}
]
}
我需要将每个带有“Re:”的标题插入到原始标题中。示例)任何回复,“Re tech:18F 演示文稿”需要插入帖子:[] 的标题:“tech:18F 演示文稿”(没有 Re:)。
我尝试将回复分成自己的 json 并将其推送到 post 数组中,但我不知道如何匹配适当的标题。
let data = [];
const original_post = [];
const reply_to_post = [];
const discourse_JSON = [];
$("item").map(function (i,article) {
const title = $(article).find("title")[0].children[0].data;
const description = $(article).find("description")[0].children[0].data;
const user_email = $(article).find("author")[0].children[0].data.match("<([^>]+)>")[1];
const link = $(article).find("link")[0].children[0].data;
const guid = $(article).find("guid")[0].children[0].data;
const date = $(article).find("pubDate")[0].children[0].data;
const name = user_email.substring(0,user_email.indexOf('@')).split("_")[0] + ' ' + user_email.substring(0,user_email.indexOf('@')).split("_")[1];
const username = user_email.substring(0,user_email.indexOf('@'))
if (
!title.toLowerCase().includes("vacancy") &&
!title.toLowerCase().includes("opportunity") &&
!title.toLowerCase().includes("retirement") &&
!title.toLowerCase().includes("position") &&
!title.toLowerCase().includes("job posting") &&
!description.toLowerCase().includes("vacancy announcement") &&
!description.toLowerCase().includes("vacancy posting") &&
!description.toLowerCase().includes("vacancies")
) {
data.push({
"title": title,"id": i,"body": description,"date": date,"author": username
}
});
解决方法
这实际上只是一个“groupBy”,通过一些字符串操作来确定层次结构。
这是一个使用 Array#reduce()
并检查标题 startsWith()
'Re:' 的示例。如果是这样,请使用 String#replace()
和 trim()
任何空格删除初始的“Re:”以保持一致性。
const
input = [{ "title": "Re: Re: Re: tech: 18F presentation","id": 3,"body": "throw more java,indeed. What a moon shot.","date": "Fri,28 May 2021 20:50:04 +0000","author": "john_doe2" },{ "title": "tech: 18F presentation","id": 2,"body": "Sadly,my biggest concern is whether it will run on Linux or Windows. And I guess if they’ll thrown even more java at it.","author": "john_doe" },{ "title": "Re: tech: 18F presentation","id": 4,"body": "Please stop saying moonshot,its not dodgecoin","author": "jane_doe" },{ "title": "Re: other: Title","id": 6,{ "title": "other: Title","id": 5,],byTopic = input.reduce((acc,{ title,...post }) => {
if (title.startsWith('Re:')) {
const topic = title.replace(/^(?:Re: ){1,}/,'').trim();
acc[topic] || (acc[topic] = { posts: [] });
acc[topic].posts.push({ title: topic,...post });
// using nullish coalescing assignment
// (acc[topic] ??= { posts: [] }).posts.push({ title: topic,...post });
} else {
acc[title] = {
id: post.id,// your example changes id in the expected output,unsure of the logic
title: title,pinned: false,// not sure where pinned is coming from
posts: acc[title] ? acc[title].posts : []
// using optional chaining and nullish coalescing
// posts: acc[title]?.posts ?? []
}
}
return acc;
},{})
console.log(Object.values(byTopic));
.as-console-wrapper { max-height: 100% !important; top: 0; }
正如我在评论中提到的,以这种方式使用 reduce()
可以直接替换为外部累加器和 for 循环。这里使用 for...of
const input = [{ "title": "Re: Re: Re: tech: 18F presentation",];
const byTopic = {};
for (const { title,...post } of input) {
if (title.startsWith('Re:')) {
const topic = title.replace(/^(?:Re: ){1,'').trim();
byTopic[topic] || (byTopic[topic] = { title: topic,posts: [] });
byTopic[topic].posts.push({ title: topic,...post });
} else {
byTopic[title] = {
id: post.id,title: title,posts: [],...byTopic[title]
}
}
};
console.log(Object.values(byTopic));
.as-console-wrapper { max-height: 100% !important; top: 0; }
这是一个使用 Array.forEach
运算符的简单解决方案。可能有更有效的解决方案,如果您有大型数据集,这可能很重要:
const source = [{title:"tech: 18F presentation",id:2,body:"Sadly,date:"Fri,author:"john_doe"},{title:"Re: tech: 18F presentation",id:3,body:"throw more java,author:"john_doe2"},id:4,body:"Please stop saying moonshot,author:"jane_doe"}];
let = formatted = [];
// Loop over the original data,find parents
source.forEach((item) => {
// Is not a reply
if (item.title.indexOf('Re:') === -1) {
formatted.push(item);
}
});
// Find children,append to parents
source.forEach((item) => {
formatted.forEach((parent) => {
// Child contains parent title.
if (item.title.indexOf(parent.title) !== -1 && item.title.indexOf('Re:') !== -1) {
if (!parent.data) {
parent.data = [];
}
parent.data.push(item);
}
})
});
console.log(formatted);