重构协助减少 JavaScript 中的一些数组数据对象

refactoring assistance with reducing some array data objects in JavaScript

我需要以某种方式减少 profiles 数组中的数据,以便最终对象根据最喜欢的电影和 liked/favorited 电影的用户对 profile obj 中的数据进行分组。 我想要这样的东西:

{
 'Forrest Gump': ["Nicholas Lain"],
 'Planet Earth 1': ["Jane Jones", "Matthew Johnson"]
}

来自以下数据对象:

const profiles = [
      {
        id: 1,
        userID: '1',
        favoriteMovieID: '1',
      },
      {
        id: 2,
        userID: '2',
        favoriteMovieID: '1',
      },
      {
        id: 3,
        userID: '4',
        favoriteMovieID: '5',
      }
    ];

    const users = {
      1: {
        id: 1,
        name: 'Jane Cruz',
        userName: 'coder',
      },
      2: {
        id: 2,
        name: 'Matthew Johnson',
        userName: 'mpage',
      }
    };

    const movies = {
      1: {
        id: 1,
        name: 'Planet Earth 1',
      },
      2: {
        id: 2,
        name: 'Selma',
      }
    };

我需要一些想法来重构以下代码,以便它返回到用户和电影对象,以从我在下面捕获的 ID 中获取他们的名字。我需要捕获名称而不是 ID。

profiles.reduce(function (acc, obj) {
    let key = obj['favoriteMovieID']
    if (!acc[key]) {
      acc[key] = []
    }
    acc[key].push(obj.userID)
    return acc
  }, {})

这是一种技术,对配置文件进行折叠,在参数中获取电影和人名,然后用该数据简单地编写一个新的累加器。请注意,这存在潜在的性能问题,如 Rich Snapp 的 excellent article 中所述。如果这给你带来了实际问题,很容易改变它来改变累加器。

我添加了一些额外的数据来显示当用户或电影不在适当的列表中时会发生什么。如果那永远不会发生,您可以稍微简化 nameperson 声明。但我不推荐它,因为 "can never happen" 事实上经常发生的事情。

const groupNamesByMovie = (profiles, users, movies) => 
  profiles .reduce ((
    a, {userID, favoriteMovieID}, _, __, 
    {name} = movies [favoriteMovieID] || {name: 'Unknown Movie'},
    {name: person} = users [userID] || {name: 'Unknown Person'}
  ) => ({
    ...a,
    [name]: [... (a [name] || []), person]
  }), {})

const profiles = [{id: 1, userID: "1", favoriteMovieID: "1"}, {id: 2, userID: "2", favoriteMovieID: "1"}, {id: 3, userID: "4", favoriteMovieID: "5"}, {id: 4, userID: "6", favoriteMovieID: "5"}, {id: 5, userID: "5", favoriteMovieID: "7"}]
const users = {1: {id: 1, name: "Jane Cruz", userName: "coder"}, 2: {id: 2, name: "Matthew Johnson", userName: "mpage"}, 4: {id: 4, name: "Nicholas Lain", userName: "nlain"}, 5: {id: 5, name: "Fred Flintstone", userName: "bedrock1"}}
const movies = {1: {id: 1, name: 'Planet Earth 1'}, 2: {id: 2, name: 'Selma'}, 5: {id: 5, name: 'Forrest Gump'}}

console .log (
  groupNamesByMovie (profiles, users, movies)
)

请注意参数 ___ 只是占位符,因为我们不关心 reduceindexarray 参数.

更新

有人要求澄清。为了比较,这里有一个更命令的版本:

const getNamesByMovie = (profiles, users, movies) =>
  profiles .reduce ((acc, {userID, favoriteMovieID}) => {
    const movie = movies [favoriteMovieID]
    const name = movie ? movie.name : 'Unknown Movie'
    const user = users [userID]
    const person = user ? user.name : 'Unknown Person'
    const fans = acc [name] || []
    return {
      ... acc,
      [name]: [... fans, person]
    }

  }, {})

如果您想避免潜在的性能问题,您可以将 return 语句替换为如下内容:

    acc [name] = fans
    fans .push (person)
    return acc

其中任何一个都与上面的原始版本做同样的事情。我选择初始样式是因为我不喜欢改变累加器对象,更喜欢始终创建一个新版本……而且因为我更喜欢使用表达式而不是语句。但这种风格确实需要一些时间来适应。

您还询问了我们如何将附加参数传递给 reduce 回调。我们没有。相反,我们定义了一些额外的参数并根据之前的参数对其进行初始化。

const profiles = [
      {
        id: 1,
        userID: '1',
        favoriteMovieID: '1',
      },
      {
        id: 2,
        userID: '2',
        favoriteMovieID: '1',
      },
      {
        id: 3,
        userID: '4',
        favoriteMovieID: '5',
      }
    ];

    const users = {
      1: {
        id: 1,
        name: 'Jane Cruz',
        userName: 'coder',
      },
      2: {
        id: 2,
        name: 'Matthew Johnson',
        userName: 'mpage',
      }
    };

    const movies = {
      1: {
        id: 1,
        name: 'Planet Earth 1',
      },
      2: {
        id: 2,
        name: 'Selma',
      }
    };
    
    
 const singleProfileNameFavoriteMovie = profiles.map(profile => `${users[profile.userID].name}'s favorite movie is  ${movies[profile.favoriteMovieID].name}` )
    

const profiles = [
  {
    id: 1,
    userID: '1',
    favoriteMovieID: '1',
  },
  {
    id: 2,
    userID: '2',
    favoriteMovieID: '1',
  },
  {
    id: 3,
    userID: '4',
    favoriteMovieID: '5',
  },
  {
    id: 4,
    userID: '5',
    favoriteMovieID: '2',
  },
  {
    id: 5,
    userID: '3',
    favoriteMovieID: '5',
  },
  {
    id: 6,
    userID: '6',
    favoriteMovieID: '4',
  },
];

const users = {
  1: {
    id: 1,
    name: 'Jane Cruz',
    userName: 'coder',
  },
  2: {
    id: 2,
    name: 'Matthew Johnson',
    userName: 'mpage',
  },
  3: {
    id: 3,
    name: 'Autumn Green',
    userName: 'user123',
  },
  4: {
    id: 4,
    name: 'John Doe',
    userName: 'user123',
  },
  5: {
    id: 5,
    name: 'Lauren Carlson',
    userName: 'user123',
  },
  6: {
    id: 6,
    name: 'Nicholas Lain',
    userName: 'user123',
  },
};

const movies = {
  1: {
    id: 1,
    name: 'Planet Earth 1',
  },
  2: {
    id: 2,
    name: 'Selma',
  },
  3: {
    id: 3,
    name: 'Million Dollar Baby',
  },
  4: {
    id: 4,
    name: 'Forrest Gump',
  },
  5: {
    id: 5,
    name: 'Get Out',
  },
};

const singleProfileFavoriteMovie = profiles.map(profile => `${users[profile.userID].name}'s favorite movie is  ${movies[profile.favoriteMovieID].name}` );

console.log(singleProfileFavoriteMovie);