如何根据另一个对象中给出的规范过滤对象?

How to filter an object according to specification given in another object?

我想根据另一个对象中给出的规范从 对象 中过滤掉数据。

例如,考虑以下 BandAndAlbums 对象,该对象包含有关 3 个乐队的 raw 数据(Beatles史密斯飞船女王):

const BandAndAlbums = {
  beatles: {
    origin: 'liverpool',
    genres: ['rock', 'pop', 'beat', 'psychedelia'],
    labels: ['parlophone', 'apple', 'capitol'],
    discography: {
      yellowSubmarine: {
        released: 1969,
        length: 39.16,
        producer: 'george martin',
        label: 'apple',
      },
      rubberSoul: {
        released: 1965,
        length: 34.55,
        producer: 'george martin',
        label: 'parlophone',
      },
      letItBe: {
        released: 1970,
        length: 35.1,
        producer: 'phil spector',
        label: 'apple',
      },
      revolver: {
        released: 1966,
        length: 35.01,
        producer: 'george martin',
        label: 'parlophone',
      },
    },
  },
  aerosmith: {
    origin: 'boston',
    genres: [
      'hard rock',
      'blues rock',
      'rock and roll',
      'glam metal',
      'heavy metal',
    ],
    labels: ['columbia', 'geffen'],
    discography: {
      doneWithMirrors: {
        released: 1985,
        length: 35.42,
        producer: 'ted templeman',
        label: 'geffen',
      },
      rocks: {
        released: 1976,
        length: 34.31,
        producer: 'jack douglas',
        label: 'columbia',
      },
      nineLives: {
        released: 1997,
        length: 62.54,
        producer: 'kevin shirley',
        label: 'columbia',
      },
    },
  },
  queen: {
    origin: 'london',
    genres: ['rock'],
    labels: [
      'emi',
      'parlophone',
      'elektra',
      'capitol',
      'hollywood',
      'island',
      'virgin emi',
    ],
    discography: {
      aNightAtTheOpera: {
        released: 1975,
        length: 43.08,
        producer: 'roy thomas baker',
        label: 'emi',
      },
      newsOfTheWorld: {
        released: 1977,
        length: 39.1,
        producer: 'queen',
        label: 'emi',
      },
      aKindOfMagic: {
        released: 1986,
        length: 40.42,
        producer: 'queen',
        label: 'emi',
      },
    },
  },
};

我想过滤 BandAndAlbums,以每个乐队仅选择专辑结束,并且每个乐队中只有 lengthproducer 属性。

如果我在下面指定我想要的相册requestedAlbums:

const requestedAlbums = {
  queen: ['aNightAtTheOpera', 'aKindOfMagic'],
  beatles: ['rubberSoul', 'letItBe', 'revolver'],
  aerosmith: ['doneWithMirrors', 'nineLives'],
};

我如何过滤 BandAndAlbums 它,并创建一个新对象,每个所选专辑只有 lengthproducer

期望输出

const desiredOutput = {
  beatles: {
    rubberSoul: {
      length: 34.55,
      producer: 'george martin',
    },
    letItBe: {
      length: 35.1,
      producer: 'phil spector',
    },
    revolver: {
      length: 35.01,
      producer: 'george martin',
    },
  },
  aerosmith: {
    doneWithMirrors: {
      length: 35.42,
      producer: 'ted templeman',
    },
    nineLives: {
      length: 62.54,
      producer: 'kevin shirley',
    },
  },
  queen: {
    aNightAtTheOpera: {
      length: 43.08,
      producer: 'roy thomas baker',
    },
    aKindOfMagic: {
      length: 40.42,
      producer: 'queen',
    },
  },
};

编辑


为了解决下面的评论,我要补充一点,我熟悉将对象转换为数组的过程(使用 Object.entries()),从而促进数组方法的使用(例如,.filter(), .map(), 等等), 最后用 Object.fromEntries().

转换回一个对象

不幸的是,在这种情况下,我有点不知道如何做我需要做的事情。我假设为了快速启动,我需要按照以下方式做一些事情:

Object.entries(BandAndAlbums).map( ([k, v]) => [k, v.discography])

(但后来我明白了 undefined

// [ [ 'queen', undefined ],
//   [ 'beatles', undefined ],
//   [ 'aerosmith', undefined ] ]

所以,如果有人能引导我走向正确的方向,我将不胜感激。谢谢。

我认为下面的函数可以解决您的需求:

const BandAndAlbums = {
  beatles: {
    origin: 'liverpool',
    genres: ['rock', 'pop', 'beat', 'psychedelia'],
    labels: ['parlophone', 'apple', 'capitol'],
    discography: {
      yellowSubmarine: {
        released: 1969,
        length: 39.16,
        producer: 'george martin',
        label: 'apple',
      },
      rubberSoul: {
        released: 1965,
        length: 34.55,
        producer: 'george martin',
        label: 'parlophone',
      },
      letItBe: {
        released: 1970,
        length: 35.1,
        producer: 'phil spector',
        label: 'apple',
      },
      revolver: {
        released: 1966,
        length: 35.01,
        producer: 'george martin',
        label: 'parlophone',
      },
    },
  },
  aerosmith: {
    origin: 'boston',
    genres: [
      'hard rock',
      'blues rock',
      'rock and roll',
      'glam metal',
      'heavy metal',
    ],
    labels: ['columbia', 'geffen'],
    discography: {
      doneWithMirrors: {
        released: 1985,
        length: 35.42,
        producer: 'ted templeman',
        label: 'geffen',
      },
      rocks: {
        released: 1976,
        length: 34.31,
        producer: 'jack douglas',
        label: 'columbia',
      },
      nineLives: {
        released: 1997,
        length: 62.54,
        producer: 'kevin shirley',
        label: 'columbia',
      },
    },
  },
  queen: {
    origin: 'london',
    genres: ['rock'],
    labels: [
      'emi',
      'parlophone',
      'elektra',
      'capitol',
      'hollywood',
      'island',
      'virgin emi',
    ],
    discography: {
      aNightAtTheOpera: {
        released: 1975,
        length: 43.08,
        producer: 'roy thomas baker',
        label: 'emi',
      },
      newsOfTheWorld: {
        released: 1977,
        length: 39.1,
        producer: 'queen',
        label: 'emi',
      },
      aKindOfMagic: {
        released: 1986,
        length: 40.42,
        producer: 'queen',
        label: 'emi',
      },
    },
  },
};



const requestedAlbums = {
  queen: ['aNightAtTheOpera', 'aKindOfMagic'],
  beatles: ['rubberSoul', 'letItBe', 'revolver'],
  aerosmith: ['doneWithMirrors', 'nineLives'],
};


// This is your desired funciton
var filterAlbum=(a,r)=>{
    var ou = {};
    for(let ri in r){
        if(typeof a[ri]!== 'undefined'){
            var our = {};
            for(let di of r[ri]){
               if(typeof a[ri].discography[di]!=='undefined'){
                    let dis = a[ri].discography[di];
                    our[di]={length:dis.length,producer:dis.producer};
                }
            }
            ou[ri] = our;
        }
    }
    return ou;
}


const desiredOutput = filterAlbum(BandAndAlbums,requestedAlbums);

console.log(desiredOutput);

如果您需要更多过滤器,可以在这里询问更多。 谢谢

您可以通过 Array.reduce()Array.entries() 的组合轻松实现此目的:

const BandAndAlbums = {
    beatles: {
        origin: 'liverpool',
        genres: ['rock', 'pop', 'beat', 'psychedelia'],
        labels: ['parlophone', 'apple', 'capitol'],
        discography: {
        yellowSubmarine: {
            released: 1969,
            length: 39.16,
            producer: 'george martin',
            label: 'apple',
        },
        rubberSoul: {
            released: 1965,
            length: 34.55,
            producer: 'george martin',
            label: 'parlophone',
        },
        letItBe: {
            released: 1970,
            length: 35.1,
            producer: 'phil spector',
            label: 'apple',
        },
        revolver: {
            released: 1966,
            length: 35.01,
            producer: 'george martin',
            label: 'parlophone',
        },
        },
    },
    aerosmith: {
        origin: 'boston',
        genres: [
        'hard rock',
        'blues rock',
        'rock and roll',
        'glam metal',
        'heavy metal',
        ],
        labels: ['columbia', 'geffen'],
        discography: {
        doneWithMirrors: {
            released: 1985,
            length: 35.42,
            producer: 'ted templeman',
            label: 'geffen',
        },
        rocks: {
            released: 1976,
            length: 34.31,
            producer: 'jack douglas',
            label: 'columbia',
        },
        nineLives: {
            released: 1997,
            length: 62.54,
            producer: 'kevin shirley',
            label: 'columbia',
        },
        },
    },
    queen: {
        origin: 'london',
        genres: ['rock'],
        labels: [
        'emi',
        'parlophone',
        'elektra',
        'capitol',
        'hollywood',
        'island',
        'virgin emi',
        ],
        discography: {
        aNightAtTheOpera: {
            released: 1975,
            length: 43.08,
            producer: 'roy thomas baker',
            label: 'emi',
        },
        newsOfTheWorld: {
            released: 1977,
            length: 39.1,
            producer: 'queen',
            label: 'emi',
        },
        aKindOfMagic: {
            released: 1986,
            length: 40.42,
            producer: 'queen',
            label: 'emi',
        },
        },
    },
};

const requestedAlbums = {
    queen: ['aNightAtTheOpera', 'aKindOfMagic'],
    beatles: ['rubberSoul', 'letItBe', 'revolver'],
    aerosmith: ['doneWithMirrors', 'nineLives'],
};

const result2 = Object.entries(requestedAlbums).reduce((tot, [k, v]) => {
    // all songs of the band
    const allSongs = BandAndAlbums[k].discography

    // take chosen ones
    const chosenSongs = v.reduce((chosen, song) => {
        chosen[song] = {
            length: allSongs[song].length,
            producer: allSongs[song].producer
        }
        return chosen
    }, {})

    // add to total
    tot[k] = chosenSongs

    return tot
}, {})

console.log(result2)

可以用Object.entries得到一个pair数组,然后做所有的映射和​​过滤,最后把得到的pair数组转回Object.fromEntries的result对象。

Object.fromEntries 也可以应用于嵌套级别以生成嵌套对象:

const BandAndAlbums = {beatles: {origin: 'liverpool',genres: ['rock', 'pop', 'beat', 'psychedelia'],labels: ['parlophone', 'apple', 'capitol'],discography: {yellowSubmarine: {released: 1969,length: 39.16,producer: 'george martin',label: 'apple',},rubberSoul: {released: 1965,length: 34.55,producer: 'george martin',label: 'parlophone',},letItBe: {released: 1970,length: 35.1,producer: 'phil spector',label: 'apple',},revolver: {released: 1966,length: 35.01,producer: 'george martin',label: 'parlophone',},},},aerosmith: {origin: 'boston',genres: ['hard rock','blues rock','rock and roll','glam metal','heavy metal',],labels: ['columbia', 'geffen'],discography: {doneWithMirrors: {released: 1985,length: 35.42,producer: 'ted templeman',label: 'geffen',},rocks: {released: 1976,length: 34.31,producer: 'jack douglas',label: 'columbia',},nineLives: {released: 1997,length: 62.54,producer: 'kevin shirley',label: 'columbia',},},},queen: {origin: 'london',genres: ['rock'],labels: ['emi','parlophone','elektra','capitol','hollywood','island','virgin emi',],discography: {aNightAtTheOpera: {released: 1975,length: 43.08,producer: 'roy thomas baker',label: 'emi',},newsOfTheWorld: {released: 1977,length: 39.1,producer: 'queen',label: 'emi',},aKindOfMagic: {released: 1986,length: 40.42,producer: 'queen',label: 'emi',},},},};

const requestedAlbums = {queen: ['aNightAtTheOpera', 'aKindOfMagic'],beatles: ['rubberSoul', 'letItBe', 'revolver'],aerosmith: ['doneWithMirrors', 'nineLives'],};

const output = Object.fromEntries(
    Object.entries(requestedAlbums).map(([band, albums]) => [
        band, 
        Object.fromEntries(
            albums.map(album => [album, BandAndAlbums[band].discography[album]])
                  .map(([album, {length, producer}]) => [album, {length, producer}])
        )
    ])
);
        
console.log(output);

这可以工作,利用对象和数组函数。

const filter = (BandAndAlbums, requestedAlbums) => Object.fromEntries(
  Object.entries(requestedAlbums).map(([name, list]) => [name, Object.fromEntries(
        list.map(entry => [entry, BandAndAlbums[name]?.discography[entry]])
      .filter(([entry, discography]) => discography)
      .map(([entry, {length, producer}]) => [entry, {length, producer}]
    ))]
  )
);

const BandAndAlbums = {
  beatles: {
    origin: 'liverpool',
    genres: ['rock', 'pop', 'beat', 'psychedelia'],
    labels: ['parlophone', 'apple', 'capitol'],
    discography: {
      yellowSubmarine: {
        released: 1969,
        length: 39.16,
        producer: 'george martin',
        label: 'apple',
      },
      rubberSoul: {
        released: 1965,
        length: 34.55,
        producer: 'george martin',
        label: 'parlophone',
      },
      letItBe: {
        released: 1970,
        length: 35.1,
        producer: 'phil spector',
        label: 'apple',
      },
      revolver: {
        released: 1966,
        length: 35.01,
        producer: 'george martin',
        label: 'parlophone',
      },
    },
  },
  aerosmith: {
    origin: 'boston',
    genres: [
      'hard rock',
      'blues rock',
      'rock and roll',
      'glam metal',
      'heavy metal',
    ],
    labels: ['columbia', 'geffen'],
    discography: {
      doneWithMirrors: {
        released: 1985,
        length: 35.42,
        producer: 'ted templeman',
        label: 'geffen',
      },
      rocks: {
        released: 1976,
        length: 34.31,
        producer: 'jack douglas',
        label: 'columbia',
      },
      nineLives: {
        released: 1997,
        length: 62.54,
        producer: 'kevin shirley',
        label: 'columbia',
      },
    },
  },
  queen: {
    origin: 'london',
    genres: ['rock'],
    labels: [
      'emi',
      'parlophone',
      'elektra',
      'capitol',
      'hollywood',
      'island',
      'virgin emi',
    ],
    discography: {
      aNightAtTheOpera: {
        released: 1975,
        length: 43.08,
        producer: 'roy thomas baker',
        label: 'emi',
      },
      newsOfTheWorld: {
        released: 1977,
        length: 39.1,
        producer: 'queen',
        label: 'emi',
      },
      aKindOfMagic: {
        released: 1986,
        length: 40.42,
        producer: 'queen',
        label: 'emi',
      },
    },
  },
};

const requestedAlbums = {
  queen: ['aNightAtTheOpera', 'aKindOfMagic'],
  beatles: ['rubberSoul', 'letItBe', 'revolver'],
  aerosmith: ['doneWithMirrors', 'nineLives'],
};

console.log(filter(BandAndAlbums, requestedAlbums));