Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
353 views
in Technique[技术] by (71.8m points)

javascript - 有什么办法可以像我在SQL中进行联接一样“联接”两个javascript数组的内容(Is there some way I can “join” the contents of two javascript arrays much like I would do a join in SQL)

I have two arrays: Question and UserProfile

(我有两个数组:Question和UserProfile)

  • The userProfiles : [] array contain { id, name } objects

    (userProfiles :[]数组包含{ id, name }对象)

  • The questions : [] array contains { id, text, createdBy } objects

    (questions :[]数组包含{ id, text, createdBy }对象)

The createdBy integer in questions is always one of the id values in userProfiles .

(问题中的createdBy整数始终是userProfiles中的id值之一。)

Is there a way I could "join" the arrays in much the same way as I would join up two SQL tables if I was using a database.

(有没有一种方法可以像我使用数据库时将两个SQL表联接起来的方式一样“联接”数组。)

What I need as an end result is an array that contains

(作为最终结果,我需要一个包含以下内容的数组)

{ id, text, name }
  ask by Alan2 translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think what you want is an inner join , which is simple enough to implement in JavaScript:

(我认为您想要的是一个内部联接 ,它很简单,可以在JavaScript中实现:)

const innerJoin = (xs, ys, sel) =>
    xs.reduce((zs, x) =>
    ys.reduce((zs, y) =>        // cartesian product - all combinations
    zs.concat(sel(x, y) || []), // filter out the rows and columns you want
    zs), []);

For the purpose of demonstration we'll use the following data set (thank you @AshokDamani):

(出于演示目的,我们将使用以下数据集(感谢@AshokDamani):)

const userProfiles = [
    {id: 1, name: "Ashok"},
    {id: 2, name: "Amit"},
    {id: 3, name: "Rajeev"},
];

const questions = [
    {id: 1, text: "text1", createdBy: 2},
    {id: 2, text: "text2", createdBy: 2},
    {id: 3, text: "text3", createdBy: 1},
    {id: 4, text: "text4", createdBy: 2},
    {id: 5, text: "text5", createdBy: 3},
    {id: 6, text: "text6", createdBy: 3},
];

This is how you would use it:

(这是您将如何使用它:)

const result = innerJoin(userProfiles, questions,
    ({id: uid, name}, {id, text, createdBy}) =>
        createdBy === uid && {id, text, name});

In SQL terms this would be similar to:

(用SQL术语,这类似于:)

SELECT questions.id, questions.text, userProfiles.name
FROM userProfiles INNER JOIN questions
ON questions.createdBy = userProfiles.id;

Putting it all together:

(放在一起:)

 const innerJoin = (xs, ys, sel) => xs.reduce((zs, x) => ys.reduce((zs, y) => // cartesian product - all combinations zs.concat(sel(x, y) || []), // filter out the rows and columns you want zs), []); const userProfiles = [ {id: 1, name: "Ashok"}, {id: 2, name: "Amit"}, {id: 3, name: "Rajeev"}, ]; const questions = [ {id: 1, text: "text1", createdBy: 2}, {id: 2, text: "text2", createdBy: 2}, {id: 3, text: "text3", createdBy: 1}, {id: 4, text: "text4", createdBy: 2}, {id: 5, text: "text5", createdBy: 3}, {id: 6, text: "text6", createdBy: 3}, ]; const result = innerJoin(userProfiles, questions, ({id: uid, name}, {id, text, createdBy}) => createdBy === uid && {id, text, name}); console.log("Open your browser console to see the output."); console.table(result); 


Edit: However this is not the best solution.

(编辑:但是,这不是最好的解决方案。)

Since the above solution loops through the Cartesian product it takes O(m × n) time to run.

(由于上述解决方案遍历笛卡尔积,因此需要O(m × n)时间来运行。)

With a little bit of modification we can make it run in O(m + n) time - @pebbl found it first :

(进行一些修改,我们可以使其在O(m + n)时间内运行-@pebbl首先找到它 :)

const equijoin = (xs, ys, primary, foreign, sel) => {
    const ix = xs.reduce((ix, row) => // loop through m items
        ix.set(row[primary], row),    // populate index for primary table
    new Map);                         // create an index for primary table

    return ys.map(row =>              // loop through n items
        sel(ix.get(row[foreign]),     // get corresponding row from primary
        row));                        // select only the columns you need
};

Now you could use it as follows:

(现在您可以按以下方式使用它:)

const result = equijoin(userProfiles, questions, "id", "createdBy",
    ({name}, {id, text}) => ({id, text, name}));

Putting it all together:

(放在一起:)

 const equijoin = (xs, ys, primary, foreign, sel) => { const ix = xs.reduce((ix, row) => ix.set(row[primary], row), new Map); return ys.map(row => sel(ix.get(row[foreign]), row)); }; const userProfiles = [ {id: 1, name: "Ashok"}, {id: 2, name: "Amit"}, {id: 3, name: "Rajeev"}, ]; const questions = [ {id: 1, text: "text1", createdBy: 2}, {id: 2, text: "text2", createdBy: 2}, {id: 3, text: "text3", createdBy: 1}, {id: 4, text: "text4", createdBy: 2}, {id: 5, text: "text5", createdBy: 3}, {id: 6, text: "text6", createdBy: 3}, ]; const result = equijoin(userProfiles, questions, "id", "createdBy", ({name}, {id, text}) => ({id, text, name})); console.log("Open your browser console to see the output."); console.table(result); 


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...