Как выполнить цикл по массиву, который уже находится внутри функции отображения, без дублирования содержимого

#javascript #reduce #array.prototype.map

#javascript #уменьшить #array.prototype.map

Вопрос:

У меня есть следующий код со следующими массивами. Я хочу перебрать их оба, извлечь некоторые данные и поместить их в конечный массив. Я могу это сделать, но содержимое дублируется. Я пытался читать о reduce, но не совсем понимаю это, и не уверен, правильное ли это решение. Я также настроил jsfiddle

https://jsfiddle.net/anders_kitson/Lcqn6fgd/

 var lineItems = [{
    id: 'li_1HyhAZHk5l44uIELgsMWqHqB',
    object: 'item',
    amount_subtotal: 7500,
    amount_total: 7500,
    currency: 'cad',
    description: 'The Spencer',
    price: [Object],
    quantity: 1
  },
  {
    id: 'li_1HyhAZHk5l44uIELeNUsiZPu',
    object: 'item',
    amount_subtotal: 7500,
    amount_total: 7500,
    currency: 'cad',
    description: 'The Gertie',
    price: [Object],
    quantity: 1
  }
]

var arr = [{
    id: 'prod_IS1wY1JvSv2CJg',
    object: 'product',
    active: true,
    attributes: [],
    created: 1606248785,
    description: 'Shelf Set',
    images: [
      'https://files.stripe.com/links/fl_test_raNEqk9ZhzX3WdQsnvXX4gFq'
    ],
    livemode: false,
    metadata: {},
    name: 'The Spencer',
    statement_descriptor: null,
    type: 'service',
    unit_label: null,
    updated: 1606248785
  },
  {
    id: 'prod_IS299dMnC13Ezo',
    object: 'product',
    active: true,
    attributes: [],
    created: 1606249543,
    description: 'Shelf Set',
    images: [
      'https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe'
    ],
    livemode: false,
    metadata: {},
    name: 'The Gertie',
    statement_descriptor: null,
    type: 'service',
    unit_label: null,
    updated: 1606249543
  }
];

let productArr = [];

arr.map((item) => {
  lineItems.map((line) => {
    productArr.push({
      image: item.images[0],
      name: item.name,
      price: line.amount_total,
    });
  });
});


console.log(productArr); 

Это результат, который я получаю, где вы можете видеть, что массив повторяет значения, и я знаю, что я закодировал его таким образом, я просто не знаю, как это исправить.

 [{
  image: "https://files.stripe.com/links/fl_test_raNEqk9ZhzX3WdQsnvXX4gFq",
  name: "The Spencer",
  price: 7500
}, {
  image: "https://files.stripe.com/links/fl_test_raNEqk9ZhzX3WdQsnvXX4gFq",
  name: "The Spencer",
  price: 7500
}, {
  image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
  name: "The Gertie",
  price: 7500
}, {
  image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
  name: "The Gertie",
  price: 7500
}]
 

Чтобы было более понятно, это тот результат, который я хочу

 [{
      image: "https://files.stripe.com/links/fl_test_raNEqk9ZhzX3WdQsnvXX4gFq",
      name: "The Spencer",
      price: 7500
    }, {
      image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
      name: "The Gertie",
      price: 7500
    }, 
]
 

Я попробовал предложение в комментариях со следующим

 let b

arr.map((item) => {
  b = lineItems.map((line) => {
    return {
      image: item.images[0],
      name: item.name,
      price: line.amount_total,
    };
  });
});
 

но он возвращает одни и те же дважды

 [{
  image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
  name: "The Gertie",
  price: 7500
}, {
  image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
  name: "The Gertie",
  price: 7500
}]
 

Комментарии:

1. map возвращает массив. Используйте это вместо push перехода к новому массиву.

2. Что находится arr на первой карте?

3. Я взял массивы из того, что сгенерировано в моем коде. На самом деле я выполняю запрос к stripe для вывода arr и выполняю другой запрос к stripe для LineItems, поэтому существуют отдельные массивы

4. @HereticMonkey если map возвращает массив, как мне получить все необходимые данные в нем в виде объекта, как видно из моего вывода?

5. Возвращает объект из функции, переданной map . Я настоятельно рекомендую ознакомиться с документацией MDN по map .

Ответ №1:

Клиппи

Хотя это и не выражено непосредственно в вашем вопросе, похоже, что вы хотите выполнить объединение в javascript. Единственное, что я вижу, связывающее эти два понятия, — это «название» в продуктах и «описание» в позициях. Так что сделайте объединение циклов по этому поводу.

Вот несколько примеров кода, использующих ваш пример, но сокращенных только до того, что имеет отношение к делу:

 var lineItems =  [
    { amount_total: 7500, description: 'The Spencer' },
    { amount_total: 7500, description: 'The Gertie' }
  ]
  
var arr = [
  { images: ['Spencer Image 1'], name: 'The Spencer' },
  { images: ['Gertie Image 1'], name: 'The Gertie' }
]


let joined = arr
  .flatMap(a => lineItems.map(li => ({a, li})))
  .filter(obj => obj.a.name == obj.li.description)
  .map(obj => ({
    image: obj.a.images[0],
    name: obj.a.name,
    price: obj.li.amount_total
  }));

console.log(joined);
     

Будучи циклическим соединением, оно может быть не столь эффективным. Выполнить хэш-соединение немного сложнее. Вы можете просмотреть исходный код моего разрабатываемого проекта fluent-data, или вам может быть даже полезно использовать его напрямую, если вы можете следовать документации.

Комментарии:

1. 1 для Clippy, я даже не читал дальше 🙂

Ответ №2:

Вы можете использовать один вызов map и ссылаться на свой второй lineItems массив либо по индексу, если вы знаете, что два массива имеют одинаковую длину и порядок

 const output = arr.map((o, i) => ({
  name: o.name, 
  image: o.images[0], 
  price: lineItems[i].amount_total}
));
 

или с помощью find() для извлечения соответствующего объекта.

 const outputUsingFind = arr.map(o => {
    const lineItem = lineItems.find(item => item.description === o.name);
    // ** add lineItem valid check here **
    return {
      name: o.name, 
      image: o.images[0], 
      price: lineItem.amount_total};
  });
 

 var lineItems = [{amount_subtotal: 7500,amount_total: 700,description: 'The Spencer',},{amount_subtotal: 7500,amount_total: 500,description: 'The Gertie',}];
var arr = [{images: ['spencer image'],name: 'The Spencer',},{images: ['gertie image'],name: 'The Gertie'}];

// since your arrays are ordered the same you can access the second object using 
// the index passed from map.
const output = arr.map((o, i) => ({
  name: o.name, 
  image: o.images[0], 
  price: lineItems[i].amount_total}
));
console.log(output);

// if the two arrays are not in the same order you can use find() to retrieve 
// the second object by property (you'll need to check 
const outputUsingFind = arr.map(o => {
    const lineItem = lineItems.find(item => item.description === o.name);
    // ** add lineItem valid check here **
    return {
      name: o.name, 
      image: o.images[0], 
      price: lineItem.amount_total};
  });
console.log(outputUsingFind); 
 .as-console-wrapper { max-height: 100% !important; top: 0; }