2017-07-18 84 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。只是想我会给你一个提醒。