Как сгруппировать массив по его вложенным элементам массива, используя Javascript? - PullRequest
0 голосов
/ 11 июля 2020

У меня есть массив song элементов, который содержит массив artists, связанный с песней

Я хотел бы сгруппировать songs по artists песни. Учитывая следующий набор данных, я бы хотел, чтобы данные были отформатированы следующим образом:

Критерии:

  • Песня должна быть частью только одной группы, поэтому, если песня несколько исполнителей, он должен храниться в группе под названием groupedArtists: "1,2" (может быть лучше соглашение об именах)
  • Не имеет значения, в каком порядке перечислены исполнители. Если в песне есть исполнители 1 и 2, а в другой песне есть исполнители 2 и 1, тогда оба должны быть сгруппированы под groupedArtists: "1,2"
var ungroupedData = [
  {
    trackId: 1,
    title: 'track 1',
    artists: [
      {
        artistId: 1,
        name: 'artist 1',
      },
      {
        artistId: 2,
        name: 'artist 2',
      },
    ],
  },
  {
    trackId: 2,
    title: 'track 2',
    artists: [
      {
        artistId: 1,
        name: 'artist 1',
      },
    ],
  },
  {
    trackId: 3,
    title: 'track 3',
    artists: [
      {
        artistId: 2,
        name: 'artist 2',
      },
      {
        artistId: 3,
        name: 'artist 3',
      },
    ],
  },
  {
    trackId: 4,
    title: 'track 4',
    artists: [
      {
        artistId: 2,
        name: 'artist 2',
      },
      {
        artistId: 1,
        name: 'artist 1',
      },
    ],
  },
]

Ниже приведен желаемый формат моих данных. Опять же, я хочу sh, чтобы не добавлять песню в группу, если она просто содержит исполнителя, она должна соответствовать каждому артисту, который будет добавлен в группу (например, если есть песня только с artist 1, ее нельзя добавлять в группу под названием groupedArtists: "1,2". Следовательно, будет создана группа под названием groupedArtists: "1", если она еще не была создана.

var groupedData = [
  {
    artistGroup: '1,2', <-- definitely open to group naming suggestions
    songs: [
      {
        trackId: 1, <-- this track has artists 1 & 2
        title: 'track 1',
        artists: [
          {
            artistId: 1,
            name: 'artist 1',
          },
          {
            artistId: 2,
            name: 'artist 2',
          },
        ],
      },
      {
        trackId: 4, <-- this track has artists 2 & 1 but they are still grouped together
        title: 'track 4',
        artists: [
          {
            artistId: 2,
            name: 'artist 2',
          },
          {
            artistId: 1,
            name: 'artist 1',
          },
        ],
      },
    ],
  },
  {
    artistGroup: '1',
    songs: [
      {
        trackId: 2, <-- track 2 only has artist 1 so `artistGroup: "1"` is created.
        title: 'track 2',
        artists: [
          {
            artistId: 1,
            name: 'artist 1',
          },
        ],
      },
    ],
  },
  {
    artistGroup: '2,3',
    songs: [
      {
        trackId: 3, <-- this song has artists 2 and 3 so we create `artistGroup: "2,3"`
        title: 'track 3',
        artists: [
          {
            artistId: 2,
            name: 'artist 2',
          },
          {
            artistId: 3,
            name: 'artist 3',
          },
        ],
      },
    ]
  }
]

Ответы [ 4 ]

0 голосов
/ 11 июля 2020
If you want to do it using map, you can refer below code.


var ungroupedData = [
  {
    trackId: 1,
    title: 'track 1',
    artists: [
      {
        artistId: 1,
        name: 'artist 1',
      },
      {
        artistId: 2,
        name: 'artist 2',
      },
    ],
  },
  {
    trackId: 2,
    title: 'track 2',
    artists: [
      {
        artistId: 1,
        name: 'artist 1',
      },
    ],
  },
  {
    trackId: 3,
    title: 'track 3',
    artists: [
      {
        artistId: 2,
        name: 'artist 2',
      },
      {
        artistId: 3,
        name: 'artist 3',
      },
    ],
  },
  {
    trackId: 4,
    title: 'track 4',
    artists: [
      {
        artistId: 2,
        name: 'artist 2',
      },
      {
        artistId: 1,
        name: 'artist 1',
      },
    ],
  },
]
    var myMap = new Map();
    for (var i=0 ; i<ungroupedData.length; i++){
        var artistIds=[];
        
        //document.write(ungroupedData[i].artists[0].artistId);
        ungroupedData[i].artists.forEach(function(artist){
            artistIds.push(artist.artistId);
        })
        artistIds.sort();
        console.log('artistIds',artistIds.join());
    
        if(myMap.has(artistIds.join())){
            debugger;
            var myExistingKey= myMap.get(artistIds.join());
            myExistingKey.songs.push(ungroupedData[i])
            myMap.set(artistIds.join(),myExistingKey)
        }
        else{
            myMap.set(artistIds.join(),{songs:[ungroupedData[i]]})
        }
        
        //myMap.set('1',1);
    }
    console.log('M', myMap);
0 голосов
/ 11 июля 2020

Не могли бы вы проверить это решение (я отредактировал ответ, чтобы удалить повторяющиеся группы исполнителей)?

var ungroupedData = [
  {
    trackId: 1,
    title: 'track 1',
    artists: [
      {
        artistId: 1,
        name: 'artist 1',
      },
      {
        artistId: 2,
        name: 'artist 2',
      },
    ],
  },
  {
    trackId: 2,
    title: 'track 2',
    artists: [
      {
        artistId: 1,
        name: 'artist 1',
      },
    ],
  },
  {
    trackId: 3,
    title: 'track 3',
    artists: [
      {
        artistId: 2,
        name: 'artist 2',
      },
      {
        artistId: 3,
        name: 'artist 3',
      },
    ],
  },
  {
    trackId: 4,
    title: 'track 4',
    artists: [
      {
        artistId: 2,
        name: 'artist 2',
      },
      {
        artistId: 1,
        name: 'artist 1',
      },
    ],
  },
];

var artistsoriginal = [];
var groupedData = [];
var isPresent = false;

ungroupedData.forEach((trk) => {
    
    if(trk.artists.length === 1) {
      groupedData.push({
        artistGroup: trk.artists[0].artistId.toString(),
        songs: [trk]
      });
    }

    if(trk.artists.length > 1) {
      let artistsArray = [];
      trk.artists.forEach((ats) => {
        artistsArray.push(ats.artistId);
      });
      const isEqual = (artistsArray.every(val => artistsoriginal.includes(val)));
      if(!isEqual) {
        artistsoriginal.push(...artistsArray);
        groupedData.push({
          artistGroup: artistsArray.toString(),
          songs: [trk]
        });
      }
    }
}
);
console.log(groupedData);
0 голосов
/ 11 июля 2020

Он кажется немного многословным и есть место для его сжатия, но вот что я бы сделал (комментарии и переменные должны внести ясность).

const dataWithGroupedIds = ungroupedData.map(track => {
  // get all the artist Ids for that track in an array
  track.allArtists = track.artists.map(t => t.artistId) 
  // remove duplicates and sort
  track.allArtists = [...new Set(track.allArtists)].sort((a,b) => a-b)
  return track
})

// get all the artistGroups and remove duplicates
const artistGroups = dataWithGroupedIds.map(t => t.allArtists).filter((t={},a=>!(t[a]=a in t))); 

// get the songs for each artistGroup
const groupedData = artistGroups.map(artistIds => {
  songs = dataWithGroupedIds.filter(track => JSON.stringify(track.allArtists) === JSON.stringify(artistIds))
  return { artistGroup: artistIds, songs } // return in desired format
})

Демо:

const ungroupedData = [
  {
    trackId: 1,
    title: 'track 1',
    artists: [
      {
        artistId: 1,
        name: 'artist 1',
      },
      {
        artistId: 2,
        name: 'artist 2',
      },
    ],
  },
  {
    trackId: 2,
    title: 'track 2',
    artists: [
      {
        artistId: 1,
        name: 'artist 1',
      },
    ],
  },
  {
    trackId: 3,
    title: 'track 3',
    artists: [
      {
        artistId: 2,
        name: 'artist 2',
      },
      {
        artistId: 3,
        name: 'artist 3',
      },
    ],
  },
  {
    trackId: 4,
    title: 'track 4',
    artists: [
      {
        artistId: 2,
        name: 'artist 2',
      },
      {
        artistId: 1,
        name: 'artist 1',
      },
    ],
  },
  {
    trackId: 5,
    title: 'track 5',
    artists: [
      {
        artistId: 2,
        name: 'artist 2',
      },
      {
        artistId: 1,
        name: 'artist 1',
      },
    ],
  },
]

const dataWithGroupedIds = ungroupedData.map(track => {
  // get all the artist Ids for that track in an array
  track.allArtists = track.artists.map(t => t.artistId) 
  // remove duplicates and sort
  track.allArtists = [...new Set(track.allArtists)].sort((a,b) => a-b) 
  return track
})

// get all the artistGroups and remove duplicates
const artistGroups = dataWithGroupedIds.map(t => t.allArtists).filter((t={},a=>!(t[a]=a in t))); 

// get the songs for each artistGroup
const groupedData = artistGroups.map(artistIds => {
  songs = dataWithGroupedIds.filter(track => JSON.stringify(track.allArtists) === JSON.stringify(artistIds))
  return { artistGroup: artistIds, songs } // return in desired format
})

console.log(groupedData)
0 голосов
/ 11 июля 2020

Возможно, вам лучше использовать словарь, который сопоставляет имена артистов (или их комбинации) с набором их песен. Например:

let groupData = {};
for(let song of ungroupedData) {
    let group_name = song.artists.map(artist => artist.artistId).sort().join(',');
    if(!(group_name in groupData)) {
        groupData[group_name] = [];
    }
    groupData[group_name].push(song);
}

Обратите внимание на сортировку художников, чтобы обеспечить стандартное представление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...