2
votes

Comment regrouper un tableau en fonction d'une clé et créer un objet dynamique avec un tableau groupé en tant que valeurs?

J'ai plusieurs éléments , dont certains avec le même titre . Je souhaite créer un tableau multidimensionnel avec le title comme première clé et un numéro unique comme deuxième clé. Il est donc possible de classer les éléments par title.

Exemple:

$itemArray = array();
foreach ($items as $key => $item) {
    $itemArray[$item['title']][] = $item;
}

Mon exemple fonctionne avec ceci code, mais à mon avis, c'est trop compliqué et j'espère qu'il existe une autre façon avec JavaScript.

{ 'booktitle':
    { '0':
      RowDataPacket {
        uid: 1,
        title: 'booktitle',
        description: 'description'  } },
    { '1':
      RowDataPacket {
        uid: 2,
        title: 'booktitle',
        description: 'description 2'  } },
  'booktitle 2':
    { '0':
      RowDataPacket {
        uid: 1,
        title: 'booktitle 2',
        description: 'description'  } }
}

L'entrée:

[ RowDataPacket {
    uid: 1,
    title: 'booktitle',
    description: 'description' },
  RowDataPacket {
    uid: 2,
    title: 'booktitle',
    description: 'description 2' },
  RowDataPacket {
    uid: 1,
    title: 'booktitle 2',
    description: 'description' } ]

Sortie attendue (comme c'est le résultat d'une requête SQL, l'élément est un RowDataPacket):

let itemArray = {}
items.forEach(item => {
    let title = item['title']

    if (itemArray[title] == null) {
      itemArray[title] = {}
    }
    let index = Object.keys(itemArray[title]).length
    itemArray[title][index] = item
  },
)

C'est facile avec PHP, là ça marche comme ça:

itemArray['title1'][0] = item1

itemArray['title1'][1] = item2

itemArray['title2'][0] = item3

Merci d'avance!


3 commentaires

Publiez votre entrée et sortie attendue :)


J'ai ajouté le résultat attendu et les données d'entrée.


@Emma Merci, mais comment utiliser .name quand le nom est aussi juste la valeur d'une autre variable?


3 Réponses :


3
votes

Vous avez la bonne idée. Le itemArray que vous avez créé n'est pas un tableau multidimensionnel. C'est un objet avec chaque titre comme clé et un tableau de éléments qui partagent le même titre que leur valeur. Vous pourriez probablement simplifier votre forEach comme ceci:

var items=[{uid:1,title:'booktitle',description:'description'},{uid:2,title:'booktitle',description:'description 2'},{uid:1,title:'booktitle 2',description:'description'}]

let itemArray = items.reduce((acc,i) => 
  ((acc[i.title] = acc[i.title] || []).push(i), acc)
,{})

console.log(itemArray)

Vérifiez si itemArray a déjà le title comme clé. Si oui, utilisez-le. Sinon, pointez-le vers un tableau vide [] . Ensuite, il suffit de push item actuel à cette propriété.

Avec reduction , vous pouvez même le simplifier en:

var items = [{
  uid: 1,
  title: 'booktitle',
  description: 'description'
}, {
  uid: 2,
  title: 'booktitle',
  description: 'description 2'
}, {
  uid: 1,
  title: 'booktitle 2',
  description: 'description'
}]

let itemArray = {}
items.forEach(item => {
  itemArray[item.title] = itemArray[item.title] || [];
  itemArray[item.title].push(item)
})

console.log(itemArray)


0 commentaires

3
votes

Vous pouvez réduire le tableau en prenant un tableau par défaut et en poussant l'élément.

var items = [{ title: 'title1' }, { title: 'title1' }, { title: 'title2' }],
    result = items.reduce((r, item) => {
        (r[item.title] = r[item.title] || []).push(item);
        return r;
    }, {});
    
console.log(result);


1 commentaires

Merci :) Il fonctionne avec cette solution et semble être le plus rapide.



0
votes

Résultat attendu

{'booktitle': {'0': RowDataPacket { uid: 1, title: 'booktitle', description: 'description'}}, { '1': RowDataPacket { uid: 2, title: 'booktitle', description: 'description 2'}}, 'booktitle 2': {'0': RowDataPacket { uid: 1, title: 'booktitle 2', description: 'description'}} }

C'est une mauvaise pratique. N'utilisez pas de propriétés énumérées sur les objets. Vous voyez à quel point ils sont encombrants. Contrairement à PHP, JS n'a pas de tableaux associatifs; donc utiliser des objets pour cela est le bon équivalent. Mais pour les tableaux indexés, vous devez utiliser des tableaux dans JS, pas des objets.

.as-console-wrapper{top:0;max-height:100%!important}
var data = [{
    uid: 1,
    title: 'booktitle',
    description: 'description'
  },
  {
    uid: 2,
    title: 'booktitle',
    description: 'description 2'
  },
  {
    uid: 1,
    title: 'booktitle 2',
    description: 'description'
  }
];

function groupBy(iterable, keyOrFn) {
  const fn = typeof keyOrFn === "function" ?
    keyOrFn :
    (item) => item == null ? undefined : item[keyOrFn];

  var result = Object.create(null);
  for (const item of iterable) {
    const key = fn(item);
    if (key in result) {
      result[key].push(item);
    } else {
      result[key] = [item];
    }
  }
  return result;
}

const booksByTitle = groupBy(data, "title");

console.log(booksByTitle);

mais il existe également de nombreux frameworks dans JS qui offrent une méthode groupBy , quelque chose comme cette implémentation rapide:

.as-console-wrapper{top:0;max-height:100%!important}
var data = [{
    uid: 1,
    title: 'booktitle',
    description: 'description'
  },
  {
    uid: 2,
    title: 'booktitle',
    description: 'description 2'
  },
  {
    uid: 1,
    title: 'booktitle 2',
    description: 'description'
  }
];

const booksByTitle = {};
for (const item of data) {
  const {
    title
  } = item;
  if (!(title in booksByTitle)) booksByTitle[title] = [];
  booksByTitle[title].push(item);
}
console.log(booksByTitle);

0 commentaires