2017-07-18 176 views
0

我試圖根據一些傳入的分頁數據更新Immutable.Map,在我的數據結構中構建頂級索引。更新ImmutableJS映射

傳入的數據是這樣的:

[ 
    { 
    identifier: ADFASD, 
    tags: [ tag1, tag2] 
    }, { 
    identifier: GGHYX, 
    tags: [ tag2, tag3] 
    }, 
] 

所需的結果

{ 
    taggedArticleList: { 
    tag1: [ADFASD], 
    tag2: [ADFASD, GGHYX], 
    tag3: [GGHYX], 
    } 
} 

目前的JS函數,我重構出(的作品):

let taggedArticleList = {} 
action.data.response.results.map((article) => { 
    article.tags.map((tag) => { 
     let key = taggedArticleList[tag] || (taggedArticleList[tag] = []; 
     key.article.push(article.identifier) 
    }); 
}); 
return taggedArticleList 

而且我目前的ImmutableJS嘗試:

.update('taggedArticleList', taggedArticleList => 
    Immutable.Map(
     Immutable.fromJS(action.data.response.results).map(
      article => 
       article.get('tags').map(
        tag => 
         [ 
          tag, 
          taggedArticleList.has('tag') 
           ? taggedArticleList.get(tag).push(article.get('identifier')) 
           : Immutable.List().push(article.get('identifier')) 
         ] 
       ) 
     ))) 

我的方法是映射傳入的數據「文章」,然後映射通過他們的「標籤」,並檢查現有的taggedArticleList是否具有密鑰 - 如果它確實向其推送新的標識符,否則創建一個新Immutable.List然後將其推入。我試圖劫持構造函數Immutable.Map,它接受[key, value]類型結構作爲創建自身的默認方式。

正在返回的數據結構給我一個奇怪的tag<List>鍵和List[tag, List[identifier]]返回形狀。任何建議非常感謝。

Data Structure

回答

1

我假設你輸入的數據也不變(這在你嘗試的解決方案暗示),即

  • 傳入整個數據集是不可變列表,
  • 每篇文章是一個不可變的地圖,並且每個系列的標記都是不可變的列表。

我的答案不包括taggedArticleList鍵,因爲該級別的對象層次結構不會增加或減少此問題的複雜性。我假設你已經包含了它,因爲它對於你的特定用例很重要,但是對於這個答案只是額外的混亂。

注意,在下面的代碼,蓄能器爲reduce功能,即jsMap,是一個正常的JavaScript地圖對象,的不可變映射對象,即jsMap是可變的。這種可變性對於此解決方案的工作是必需的,並且(我相信)不違反使用不可變數據的原則,因爲它只是在處理原始傳入數據期間使用的中間變量,並且最終轉換爲不可變地圖。

如上所述,此解決方案假定您的傳入數據也是不可變的。但是,如果它只是「正常」(可變的)JavaScript對象數據,則您需要做的唯一一件事就是將article.get('tags')更改爲article.tags,並將article.get('identifier')更改爲article.identifier

const incoming = Immutable.List([ 
    Immutable.Map({ 
    identifier: 'ADFASD', 
    tags: Immutable.List([ 'tag1', 'tag2']) 
    }), 
    Immutable.Map({ 
    identifier: 'GGHYX', 
    tags: Immutable.List([ 'tag2', 'tag3']) 
    }), 
]); 

const updated = Immutable.Map(
    incoming.reduce((jsMap, article) => { 
     article.get('tags').forEach(tag => { 
      jsMap.set(tag, Immutable.List([ 
       ...(jsMap.has(tag) ? jsMap.get(tag) : []), 
       article.get('identifier') 
      ])); 
     }); 
     return jsMap; 
    }, new Map()) // NOTE: this is a regular JavaScript map, NOT an Immutable map 
); 

console.log(updated); 

// console output: Map { "tag1": List [ "ADFASD" ], "tag2": List [ "ADFASD", "GGHYX" ], "tag3": List [ "GGHYX" ] } 

正如一個側面說明,也請注意,在你原來的解決方案,無論是原工作的JavaScript代碼和非工作不可變的代碼,我想你使用map不當,即使在第一情況下,你最終得到你想要的解決方案。 map是一個函數,用於返回一個數組,其中每個元素對應於原始數組中的元素。您正在使用它來按順序獲取每個元素,但只需使用該元素修改其他數據而不從該函數返回任何內容。事實上,你想要的最終結果是而不是具有映射(即對應)到原始數組的數組元素。事實上,結果甚至不是一個數組,它是一個對象(或者更準確地說,一個Map ...我知道,它變得混亂)。我認爲在這種情況下,你可能應該使用類似forEach而不是map。這段時間你的代碼工作,但以這種方式使用map函數可能會導致未來的混淆/錯誤。你使用它的方式不是非法的,並且如你所示,可以工作。但是,這不是打算如何使用map。只是想我會給你一個提醒。