介紹
我正在實施一種方法,該方法將帖子插入到我的地圖中的相應用戶帖子串列中,按日期排序(最近的帖子優先)。
這就是我構建資料的方式:
state = {
userId: {
posts: [
{ // object returned from my feeds algorithm in the server side
id,
userData: {
id,
},
date,
},
... more posts ...
],
},
... more users ...
}
在我的演算法中,我只需要插入給定串列中的所有帖子
[
{ id: "post1", { userData: { id: "alex" }, date },
{ id: "post2", { userData: { id: "sara" }, date }
]
在每個用戶的帖子串列中。
問題
我還需要避免插入我所在州已經存在的帖子,而且我找不到一種簡單的方法來優化它。
當前代碼
這是我目前的實作。我覺得這可以更容易、更快地完成。有什么幫助嗎?
/*
Algorithm
*/
function addContents(state, contents, contentType, cached) {
const newState = state;
contents.forEach((content) => {
const { userData: { id: userId } } = content;
const prevUserState = state.get(userId);
const prevContents = prevUserState?.[contentType] ?? [];
const newContents = prevContents;
// TODO - Avoid inserting if already exists in prevContents! (check by **id**)
let inserted = false;
for (const [index, prevContent] of prevContents.entries()) {
// Replace
if (content.id === prevContent.id) {
newContents[index] = content;
inserted = true;
break;
}
// Insert in the correct order
if(content.date >= prevContent.date) {
newContents.splice(index, 0, content);
inserted = true;
break;
}
}
if (!inserted) {
newContents.push(content);
}
newState.set([
userId,
{
...prevUserState,
[contentType]: newContents
}
]);
});
// if(isEqual(state, newState)) return state; (deep compare to avoid re-renderizations because of state update)
return new Map([...newState]);
}
/*
Test
*/
(() => {
// State
const state = new Map([]);
// User ALEX
const userId1 = "alex";
const userPosts1 = [ // already sorted by date
{
id: "78q78w0w0",
userData: {
id: userId1,
},
date: new Date("10/26/1999 00:00:01")
},
{
id: "92uwdq092",
userData: {
id: userId1,
},
date: new Date("10/26/1999 00:00:00")
}
];
state.set(userId1, { posts: userPosts1 });
// User SARA
const userId2 = "sara";
const userPosts2 = [ // already sorted by date
{
id: "iipzxx115",
userData: {
id: userId2,
},
date: new Date("12/25/2003 03:30:10")
},
{
id: "Wxrr22232",
userData: {
id: userId2,
},
date: new Date("01/01/2000 17:44:41")
}
];
state.set(userId2, { posts: userPosts2 });
const newPosts = [
{
id: "OLDEST FOR ALEX!",
userData: {
id: userId1
},
date: new Date("10/25/1999 23:59:59")
},
{
id: "NEWEST FOR SARA!",
userData: {
id: userId2
},
date: new Date("01/05/2010 22:22:22")
},
{
id: "OLDEST FOR SARA!",
userData: {
id: userId2
},
date: new Date("10/25/1999 23:59:59")
}
]
addContents(state, newPosts, "posts");
console.log(state.get(userId1))
console.log(state.get(userId2))
})();
注意:由于這個方法是在 React 的 reducer 中實作的,為了管理復雜的狀態,我回傳一個新的 Map,在深入比較之前和新的狀態后,生成 UI 重新渲染。
更新
I have implemented another version where I do what I need, but maybe, it can be more optimized.
function addContents(state, contents, contentType, cached) {
const newState = state;
const exists = {}; // optimization
for (const content of contents) {
const {
userData: { id: userId },
} = content;
const prevUserState = state.get(userId);
const prevContents = prevUserState?.[contentType] ?? [];
const newContents = prevContents;
if (cached) {
if (!exists[userId]) {
exists[userId] = prevContents.reduce((map, content) => {
map[content.id] = true;
return map;
}, {});
}
// Avoid inserting if necessary
if (exists[userId][content.id]) {
break;
}
}
// Insert the new content in the user's content list
console.log(`Inserting ${content.id}`);
let inserted = false;
for (const [index, prevContent] of prevContents.entries()) {
// Replace
if (content.id === prevContent.id) {
newContents[index] = content;
inserted = true;
break;
}
// Insert in the correct order
if(content.date >= prevContent.date) {
newContents.splice(index, 0, content);
inserted = true;
break;
}
}
if (!inserted) {
newContents.push(content);
}
newState.set([
userId,
{
...prevUserState,
[contentType]: newContents
}
]);
}
// if (isEqual(state, newState)) return state;
return new Map([...newState]);
}
/*
Test
*/
(() => {
// State
let state = new Map([]);
// User ALEX
const userId1 = "alex";
const userPosts1 = [ // already sorted by date
{
id: "78q78w0w0",
userData: {
id: userId1,
},
date: new Date("10/26/1999 00:00:01")
},
{
id: "92uwdq092",
userData: {
id: userId1,
},
date: new Date("10/26/1999 00:00:00")
}
];
state.set(userId1, { posts: userPosts1 });
// User SARA
const userId2 = "sara";
const userPosts2 = [ // already sorted by date
{
id: "iipzxx115",
userData: {
id: userId2,
},
date: new Date("12/25/2003 03:30:10")
},
{
id: "Wxrr22232",
userData: {
id: userId2,
},
date: new Date("01/01/2000 17:44:41")
}
];
state.set(userId2, { posts: userPosts2 });
const newPosts = [
{
id: "OLDEST FOR ALEX!",
userData: {
id: userId1
},
date: new Date("10/25/1999 23:59:59")
},
{
id: "NEWEST FOR SARA!",
userData: {
id: userId2
},
date: new Date("01/05/2010 22:22:22")
},
{
id: "OLDEST FOR SARA!",
userData: {
id: userId2
},
date: new Date("10/25/1999 23:59:59")
}
]
state = addContents(state, newPosts, "posts");
console.log(state.get(userId1))
console.log(state.get(userId2))
/*
Insert again!
*/
state = addContents(state, newPosts, "posts", true);
})();
uj5u.com熱心網友回復:
使用物件而不是陣列:這與normalizrredux 庫的概念相同:https : //github.com/paularmstrong/normalizr
state = {
[user1Id]: {
posts: {
[post1Id]: {
id,
userData: {
id,
},
date,
},
[post2Id]: {
id,
userData: {
id,
},
date,
},
... more posts ...
},
},
... more users ...
}
通過這種方式,您可以通過其 Id 輕松訪問您想要的物件并檢查它是否存在或不這樣做:if(state[23].posts[12])
如果您需要迭代用戶或用戶發布使用
object.keys(state).map(userId => ...)
或者
object.keys(state[23].posts).map(postId => ...)
插入/更新:
state[23].posts[newId]: { ...newPost}
uj5u.com熱心網友回復:
我無法關注您在做什么,但我認為這就是您所追求的。你可以很容易地在一個單行上做到這一點。
newdata = [{ id: "post1", { userData: { id: "alex" }, date }]
if(!oldstates.find(d =>
d.id === newdata.id &&
d.userData.id === newdata.userData.id &&
d.date === newdata.date
)) {
oldstates.push(newdata)
}
// oneliner
if(!oldstates.find(d => d.id === newdata.id && d.userData.id === newdata.userData.id && d.date === newdata.date )) oldstates.push(newdata)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/344373.html
標籤:javascript reactjs algorithm data-structures ecmascript-6
上一篇:從1到n的二進制數計數
下一篇:查找重復的單詞
