Как использовать Array.protoype.map() для массива объектов, чтобы отфильтровать некоторые конкретные ключи на основе их значений?

У меня есть следующий массив объектов, в котором некоторые определенные ключи имеют значение, которое является либо строкой, либо массивом. Я хочу получить ключи со строковыми значениями как есть и удалить «NA» из ключей со значениями массива.

Я пытаюсь добиться того же, выполняя метод .map для массива, проверяя тип значения каждого ключа в объекте данных, если массив, то используйте .filter для удаления значений «NA».

var dataArr = [
    {
     a: 'foo',
     b: [1, 2, "NA", "NA", 3],
     c: ["NA", 6]
    },
    {
     a: 'bar',
     b: ["NA", "NA", "NA"],
     c: []
    }
];
dataArr.map(dataObj => {
    for (let key in dataObj) {
        if (key !== 'a')
            dataObj[key] = dataObj[key].filter(val => { if (val != "NA") return val})
    }
    return dataObj;
});

Приведенный выше блок кода работает, как и ожидалось, но мне нужно лучшее и перспективное решение. Более того, это тоже плохо выглядит.

Ваш текущий код мутирующий оригинальный dataArr, это действительно желательно?

CertainPerformance 27.05.2019 10:43
dataArr[0].map не получится. Вы используете карту на объекте JS. Объекты не имеют функции карты.
Shubham 27.05.2019 10:48

@Shubham, спасибо, что указали, это опечатка. Я редактирую вопрос.

sibasishm 27.05.2019 10:53

@CertainPerformance Да, я знаю о проблеме мутации, спасибо, что указали. Но мутация здесь не окажет никакого влияния, так как я убираю ненужные значения.

sibasishm 27.05.2019 10:56
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
4
112
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Используйте for...of для записей объекта. Для каждой записи проверьте, является ли она массивом. Если это фильтр массива, а затем назначьте новый объект. Если нет, назначьте без фильтрации. Это не изменит исходный массив.

const dataArr = [{"a":"foo","b":[1,2,"NA","NA",3],"c":["NA",6]},{"a":"bar","b":["NA","NA","NA"],"c":[]}]

const result = dataArr.map(dataObj => {
  const filterObject = {};
  
  for (const [key, val] of Object.entries(dataObj)) {
    filterObject[key] = Array.isArray(val) ?
      dataObj[key].filter(val => val != 'NA')
      :
      val;
  }
  
  return filterObject;
});

console.info(result);

Вы можете сделать это, используя вложенные map() и filter()

  • Прежде всего используйте map() на основном массиве.
  • Затем получите записи каждого объекта, используя Object.entries()
  • Затем используйте map() для записей каждого объекта.
  • Верните значение как есть, если Array.isArray равно false, в противном случае верните отфильтрованное значение массива.
  • Наконец, используйте Object.fromEntries(), чтобы создать объект.

var dataArr = [
    {
     a: 'foo',
     b: [1, 2, "NA", "NA", 3],
     c: ["NA", 6]
    },
    {
     a: 'bar',
     b: ["NA", "NA", "NA"],
     c: []
    }
];

const res = dataArr.map(x => 
               Object.fromEntries(
                   Object.entries(x)
                     .map(([k,v]) => 
                        [k,Array.isArray(v) ? v.filter(b => b !== "NA") : v])
                     )
               )

console.info(res)

Спасибо за ответ, но я не думаю, что это решает проблему временной сложности.

sibasishm 27.05.2019 11:02

@SibasishMohanty Вы ничего не упомянули о временной сложности в вопросе. В чем проблема с временной сложностью?

Maheer Ali 27.05.2019 11:06

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

sibasishm 27.05.2019 11:09
Ответ принят как подходящий

Если вы просто хотите обновить исходный массив, вы можете прокрутить массив, используя forEach. Затем переберите ключи каждого объекта, используя for...in, и проверьте, является ли он массивом, используя Array.isArray(). Обновите свойство после фильтрация из значения NA

const dataArr = [{a:'foo',b:[1,2,"NA","NA",3],c:["NA",6]},{a:'bar',b:["NA","NA","NA"],c:[]}];

dataArr.forEach(o => {
  for (const key in o) {
    if (Array.isArray(o[key]))
      o[key] = o[key].filter(s => s !== "NA")
  }
})

console.info(dataArr)

Если вы хотите получить новый массив без изменения исходных объектов, вы можете использовать map следующим образом:

const dataArr = [{a:'foo',b:[1,2,"NA","NA",3],c:["NA",6]},{a:'bar',b:["NA","NA","NA"],c:[]}];

const newArray = dataArr.map(o => {
  const newObj = {};
  
  for (const key in o) {
    if (Array.isArray(o[key]))
      newObj[key] = o[key].filter(s => s !== "NA")
    else
      newObj[key] = o[key]
  }
  
  return newObj;
})

console.info(newArray)

    const dataArr = [{
            a: 'foo',
            b: [1, 2, "NA", "NA", 3],
            c: ["NA", 6]
        },
        {
            a: 'bar',
            b: ["NA", "NA", "NA"],
            c: []
        }
    ];

    const res = dataArr.map((obj) => {
        for(let i in obj){
            if (Array.isArray(obj[i])){
                obj[i] = obj[i].filter(el=>el!= = "NA")
            }
        }
        return obj;
    });

    console.info('@>res', res)

Спасибо за ответ, но количество ключей в моем объекте слишком велико, чтобы проверять все их значения по отдельности.

sibasishm 27.05.2019 10:59

Я предполагаю, что это будет лучший рефакторинг кода, пожалуйста, предоставьте также желаемый результат:

dataArr.forEach(object=>{
  for (let value in object){
   let isArr = Object.prototype.toString.call(data) == '[object Array]';
   isArr? object[value] = object[value].filter(val => {return val != "NA"}):null}
 })
typeofмассив тоже "object".
adiga 27.05.2019 17:30

Я отредактировал решение, пожалуйста, проверьте его, ссылка на stackoverflow.com/questions/12996871/…

vishnu prasath 28.05.2019 08:08

Другие вопросы по теме