首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >仅使用纯函数的反转对象

仅使用纯函数的反转对象
EN

Stack Overflow用户
提问于 2015-01-18 11:57:21
回答 3查看 132关注 0票数 3

假设您有这样一个对象:

代码语言:javascript
复制
{
  a: [1,2,3],
  b: [2],
  c: [1,4]
}

你需要把它转换成:

代码语言:javascript
复制
{
  1: ['a', 'c'],
  2: ['a', 'b'],
  3: ['a'],
  4: ['c']
}

使用命令式方式和可变的数据结构很容易做到这一点:

代码语言:javascript
复制
function convert (obj) {
  var key, values
    , result = {};

  for (key in obj) {
    values = obj[key];
    values.forEach(function (value) {
      result[value] = result[value] || []; // bad — mutability :(
      result[value].push(key); // bad — mutability :(
    });
  }

  return result;
}

但是,是否有任何方法来做到这一点,只使用纯函数,而不使用任何分配?允许使用某些库进行函数式编程。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-01-18 12:21:40

嗯,这是一个纯粹的数据转换,所以您肯定可以不使用可变变量来完成它。让我们在Haskell中这样做,它为我们提供了一个静态的保证,即没有显式的变异。我们从一个例子开始:

代码语言:javascript
复制
d :: [(Char, [Integer])]
d = [('a', [1,2,3]), ('b', [2]), ('c', [1,4])]

好的,那么新结构的关键是什么?它们是第一种结构的独特元素:

代码语言:javascript
复制
> import Data.List
> let keys = sort . nub . concatMap snd $ d
[1,2,3,4]

然后我们需要知道每个值出现在哪个列中。因此,将每个值与其键配对:

代码语言:javascript
复制
> let pairs = concatMap (\(k,v) -> map (,k) v) d
[(1,'a'),(2,'a'),(3,'a'),(2,'b'),(1,'c'),(4,'c')]

现在我们可以构建这样的结果:

代码语言:javascript
复制
 > [ (k, map snd . filter ((== k) . fst) $ pairs ) | k <- keys ]
 [(1,"ac"),(2,"ab"),(3,"a"),(4,"c")]

在它的荣耀中:

代码语言:javascript
复制
{-# LANGUAGE TupleSections #-}

import Data.List

rotate d = [ (k, map snd . filter ((== k) . fst) $ pairs ) | k <- keys ]
    where
        keys  = sort . nub . concatMap snd $ d
        pairs = concatMap (\(k,v) -> map (,k) v) d

例如。

代码语言:javascript
复制
*A> rotate [('a', [1,2,3]), ('b', [2]), ('c', [1,4])]
[(1,"ac"),(2,"ab"),(3,"a"),(4,"c")]

或者没有命名中间结构的无点版本:

代码语言:javascript
复制
rotate2  = map (\x -> (head (map fst x), map snd x))
         . groupBy ((==) `on` fst)
         . sortBy (comparing fst)
         . concatMap (\(k,v) -> map (,k) v)

很好的小面试问题:)

票数 5
EN

Stack Overflow用户

发布于 2015-01-18 14:52:54

找到了一种使用兰达库进行此操作的方法:

代码语言:javascript
复制
compose(
  reduce(function(acc, key) {
    return assoc(key, filter(compose(contains(key), propOf(src)), keys(src)), acc);
  }, {}),
  uniq,
  flatten,
  values
)(src)
票数 1
EN

Stack Overflow用户

发布于 2015-01-19 08:29:16

给定像Haskell的Data.Map这样的关联数据结构,我会为每对(v, ks) :: (String, [Int])创建几个只包含k |-> [v]的映射(即每个键映射到包含唯一值的单例列表),然后将它们合并。

与Haskell语法保持一致,这将使您得到以下内容:

代码语言:javascript
复制
import qualified Data.Map as Map

insideOut :: (Ord k) => [(v, [k])] -> [(k, [v])]
insideOut vks = Map.toList . Map.unionsWith (++) $
                [ Map.singleton k [v] | (v, ks) <- vks, k <- ks]
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28009393

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档