0
votes

Array.reduce () groupe par champ d'objet et étend tous les autres champs à leur champ d'objet groupé correspondant

Je veux créer une fonction group-By pour un objet, où je regroupe un tableau par un champ, puis je "contraint" en quelque sorte tous les champs des documents à venir du tableau par leurs champs d'objet de groupe correspondants.

pre> XXX

J'ai maintenant le problème comment puis-je étendre les champs des objets groupés par leurs autres champs d'objet correspondants à partir des objets du tableau?

Par exemple, si mon objet groupé a un sous-document pour une clé de groupe avec un tableau de champs et un champ "chaîne", alors je veux pousser toutes les nouvelles valeurs de tableau des objets de groupe correspondants dans l'ancien tableau, et aussi je veux forcer les chaînes avec "+" .. . comment puis-je faire cela?

MODIFIER : Mes données d'origine:

CarDocs:  { Ford: { prices: ["12", "3", "5", "1", '99', '88', '77' ], model: 'T3', 'SUV' },
  Toyota: { prices: [33","44","55", '66', '50', '22' ], model: 'Cheyenne', 'Subaru' },
  Peugeot: { prices: [ '1', '2', '3' ], model: '503' } }

Mon résultat est:

CarDocs:  { Ford: { prices: [ '99', '88', '77' ], model: 'T3' },
  Toyota: { prices: [ '66', '50', '22' ], model: 'Cheyenne' },
  Peugeot: { prices: [ '1', '2', '3' ], model: '503' } }

mais cela devrait être:

let doc = [
    {
        "car": "Ford",
        "prices": ["12", "3", "5", "1"],
        "model": "SUV"
    },
    {
        "car": "Ford",
        "prices": ["99","88","77"],
        "model": "T3"
    },
    {
        "car": "Toyota",
        "prices": ["33","44","55"],
        "model": "Subaru"
    },
    {
        "car": "Toyota",
        "prices": ["66", "50", "22"],
        "model": "Cheyenne"
    },
    {
        "car": "Peugeot",
        "prices": ["1","2","3"],
        "model" : "503"
    }
];


3 commentaires

Pouvez-vous publier vos données originales? Je voulais dire ce tableau initial


oui désolé, je l'ai ajouté dans mon message d'origine


model devra être un tableau ici, ou une seule chaîne.


3 Réponses :


1
votes

Vous devez fusionner les valeurs avec la valeur précédente, alors que dans votre code, vous attribuez de nouvelles valeurs à chaque itération

let doc = [{"car": "Ford","prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford","prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];

let final = doc.reduce((op,{car,prices,model:m})=>{
  op[car] = op[car] || {prices:[],model:[]}
  op[car].prices = [...op[car].prices, ...prices]
  op[car].model = [...op[car].model, m]
  return op
},{})

console.log(final)


0 commentaires

2
votes

Vous pouvez fusionner chaque objet en fonction du nom de clé de chaque boucle avec Reduce:

let doc = [{"car": "Ford", test: 'test', "prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford", test: 'test', "prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];

let CarDoc = doc.reduce((a, {car, ...rest}) => {
  Object.entries(rest).forEach(([k,v]) => {
    if(a[car]) {
      a[car][k] = [...a[car][k] || [], v]
    } else {
      a[car] = {...a[car], [k]: [v]}
    }
  })
  
  return a
}, {})

console.log(CarDoc)

Version moins lisible, sur une seule ligne:

let doc = [{"car": "Ford","prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford","prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];

let CarDoc = doc.reduce((a, {car, prices, model}) => a[car] ? {...a, [car]: {prices: a[car].prices.concat(prices), model: a[car].model.concat(model)}} : {...a, [car]: {prices, model:[model]}}, {})

console.log(CarDoc)

EDIT:

let doc = [{"car": "Ford","prices": ["12", "3", "5", "1"],"model": "SUV"},{"car": "Ford","prices": ["99","88","77"],"model": "T3"},{"car": "Toyota","prices": ["33","44","55"],"model": "Subaru"},{"car": "Toyota","prices": ["66", "50", "22"],"model": "Cheyenne"},{"car": "Peugeot","prices": ["1","2","3"],"model" : "503"}];

let CarDoc = doc.reduce((a, {car, prices, model}) => {
  if(a[car]) {
    prices.forEach(p => a[car].prices.push(p))
    a[car].model = [...a[car].model, model]
  } else {
    a[car] = {prices, model:[model]}
  }
  return a
}, {})

console.log(CarDoc)


6 commentaires

merci, mais y a-t-il un moyen de généraliser le code, afin qu'il fonctionne pour tous les champs et types de champs? Dois-je vérifier de quel type de champ le champ est-il?


Vous pourriez, mais oui, vous devrez vous accommoder du type. Je pense que lorsque vous fusionnez les prix, il serait préférable de les avoir dans un format comme [[1,2,3], [4,5,6]] lors de la fusion, afin que vous puissiez accéder valeurs liées par index. Ainsi, vous pouvez tout mettre dans un tableau et pousser les valeurs dans le tableau correspondant à chaque fois.


joli,. Je suis impressionné de voir à quel point c'est "facile" (en lignes de code). J'essayais pendant quelques heures de faire les choses correctement, je l'ai compris mais bien plus compliqué que cela, pouvez-vous m'expliquer où vous avez appris cela? Et que signifie une [voiture] [k] = [... une [voiture] [k] || [], v] faire? Je sais qu'il crée la clé a [car] [k] à la volée si elle n'existe pas, mais [... a [car] [k] || [], v] crée un tableau avec la valeur a [voiture] [k] avec un tableau vide comme solution de secours, ou la valeur elle-même? Qu'est-ce que ça veut dire?


Vous avez raison, ... répartira toutes les propriétés existantes, mais s'il n'y en a pas, il se repliera sur un tableau vide.


ok merci, pour moi en tant que débutant, il est assez difficile d'arriver à une solution aussi propre et compacte ..


@ user2774480 pas de soucis. Si vous avez besoin de plus d'aide, n'hésitez pas à demander :)



0
votes

Prise sans vergogne. Ma bibliothèque blinq fournit un certain nombre de fonctions qui rendent ce type transformation facile:

<script src="https://cdn.jsdelivr.net/npm/blinq"></script>

const doc = [{
    "car": "Ford",
    "prices": ["12", "3", "5", "1"],
    "model": "SUV"
  },
  {
    "car": "Ford",
    "prices": ["99", "88", "77"],
    "model": "T3"
  },
  {
    "car": "Toyota",
    "prices": ["33", "44", "55"],
    "model": "Subaru"
  },
  {
    "car": "Toyota",
    "prices": ["66", "50", "22"],
    "model": "Cheyenne"
  },
  {
    "car": "Peugeot",
    "prices": ["1", "2", "3"],
    "model": "503"
  }
];

const {
  blinq
} = window.blinq

const result = blinq(doc)
  .groupBy(c => c.car)
  .select(g => ({
    car: g.key,
    prices: g
      .selectMany(c => c.prices)
      .distinct()
      .toArray(),
    models: g.select(c => c.model).toArray()
  }))
  .toArray();
console.log(result)
const result = blinq(doc)
  .groupBy(c => c.car)
  .select(g => ({
    car: g.key,
    prices: g
      .selectMany(c => c.prices)
      .distinct()
      .toArray(),
    models: g.select(c => c.model).toArray()
  }))
  .toArray();


1 commentaires

Je ne vais pas mentir, cela rend les choses beaucoup plus difficiles à lire. Belle bibliothèque, cependant.