Учитывая массив объектов, как вы создаете новый массив объектов с разными именами ключей, в то же время пропуская нежелательные данные (путь ES6)? - PullRequest
0 голосов
/ 05 декабря 2018

Извините за заголовок, он ограничен 150 символами.

Пример полного кода:

https://jsfiddle.net/c81zw30m/

Данные:

Допустим, я делаю запрос API и получаю возвращенный объект JSON:

[
    {
        id: 123,
        person: {
            data: {
                name: 'John',
                language: 'Javascript'
            }
        },
        details: {
            age: 25
        },
        has_experience: true
    },
    {
        id: 456,
        person: {
            data: {
                name: 'Peter',
                language: null // here we have null as a value.
            }
        },
        details: {
            age: 40
        },
        has_experience: false
    },
    {
        id: 789,
        person: {
            data: {
                name: 'Paul',
                language: 'Python'
            }
        },
        details: {
            age: 30
        },
        has_experience: null // and here we also don't know if the person is available
    },
];

Цель:

Конечная цельздесь нужно перебрать массив и получить новый массив объектов с разными именами ключей.Например, я хочу заменить ключ person на human или ключ available на availability.

Кроме того (дополнительно) мы хотим пропустить добавление ключей, значение которых равноnull.

Текущее решение:

let results = [];

for (let i=0; i< json.length; i++) {

    results.push({
        user_id: json[i].id,
        name: json[i].person.data.name,
        age: json[i].details.age,
        has_experience: json[i].available ? json[i].available : false // here we are assigning a value no matter what using a ternary operator, what if we want no key:value pair here, just skip that pair
    });

    if (json[i].person.data.language) { results[i].language = json[i].person.data.language }
}

console.log(results);

Проблема:

Теперь приведенный мной пример и решение работает, но представьте, если бы исходный запрос API имел сотни пар ключ: значение, и многие из них могли бы иметь значение null.

Вопрос:

Использование современныхjavascript, есть ли какой-нибудь менее многословный и более чистый и элегантный способ решения этой проблемы?

В целом, я ищу создание совершенно нового массива объектов на основе оригинального, но с новыми именами ключей, где это необходимо,Кроме того, мы хотим пропустить добавление некоторых из них, например, если значение ключа равно null.

Cheers.


EDIT:

Изменилось имя ключа из примера, изначально предоставленного с available на has_experience, потому что это немного вводило в заблуждение.Я не ищу, чтобы отфильтровать исходный массив объектов на основе значения данного ключа.Если бы я хотел сделать это, я бы начал с filter, а затем включил цепочку.

Что я хочу сделать, это исключить добавление пары ключ: значение во вновь сформированный массив, если значение ключаэто null например.

Ответы [ 4 ]

0 голосов
/ 05 декабря 2018

Используя lodash (или аналогичный), вы можете получить определение отображения из цикла отображения.Я считаю следующее довольно кратким, хотя, вероятно, его можно еще немного сократить.

import { get, set } from "lodash";

let json = [ ... ];

let mapping = new Map([
  ["user_id", "id"],
  ["name", "person.data.name"],
  ["age", "details.age"],
  ["availability", "available"],
  ["language", "person.data.language"],
  ["some.nested.property", "person.data.language"]
]);

var results = json.map(element => {
  var mappedElement = {};
  mapping.forEach((path, field, map) => {
    var value = get(element, path);
    if (value) {
      set(mappedElement, field, value);
    }
  });
  return mappedElement;
});

console.log(results);

Выполнение этого на ваших данных дает

[Object, Object, Object]
0: Object
  user_id: 123
  name: "John"
  age: 25
  availability: true
  language: "Javascript"
  some: Object
    nested: Object
      property: "Javascript"
1: Object
  user_id: 456
  name: "Peter"
  age: 40
2: Object
  user_id: 789
  name: "Paul"
  age: 30
  language: "Python"
  some: Object
    nested: Object
      property: "Python"

Рабочий пример: https://codesandbox.io/s/mnkp79668

0 голосов
/ 05 декабря 2018

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

const list = [
    {
        id: 123,
        person: {
            data: {
                name: 'John',
                language: 'Javascript'
            }
        },
        details: {
            age: 25
        },
        available: true
    },
    {
        id: 456,
        person: {
            data: {
                name: 'Peter',
                language: null // here we have null as a value.
            }
        },
        details: {
            age: 40
        },
        available: false
    },
    {
        id: 789,
        person: {
            data: {
                name: 'Paul',
                language: 'Python'
            }
        },
        details: {
            age: 30
        },
        available: null // and here we also don't know if the person is available
    },
];

const newList = list.filter(listItem => listItem.available).map(filteredItem => {
  return {
        user_id: filteredItem.id,
        name: filteredItem.person.data.name,
        age: filteredItem.details.age,
        availability: !!filteredItem.available
    }
})

document.getElementById('list').innerText = JSON.stringify(list, null, 2);
document.getElementById('newList').innerText = JSON.stringify(newList, null, 2);
.container {
  display: flex;
}

.container pre {
  flex: 0 0 50%;
}

0 голосов
/ 05 декабря 2018

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

Эта функция рекурсивно сглаживает вложенный объект, вдольспособ без каких-либо null значений.Однако эта функция может перезаписывать любые значения, когда один и тот же ключ существует на нескольких уровнях, поэтому см. Ниже.

function flatten(obj, dest) {
    for (let key in obj) {
        if (typeof obj[key] === 'object') {
            flatten(obj[key], dest);
        } else if (obj[key] !== null) {
            dest[key] = obj[key];
        }
    } 
    return dest;
}

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

function remap(obj, keys) {
    for (let [in_key, out_key] of keys) {
        let val = _.get(obj, in_key, null);
        if (val !== null) {
                _.unset(obj, in_key);
                _.set(obj, out_key, val);
        }
    }
    return obj;
}

Функции могут быть объединены в цепочку, как это:

let in_map = new Map([
    ['user.id', 'user_id']
]);

let out_map = new Map([
    ['available', 'test.availability']
]);

let out = data.map(obj => remap(obj, in_map))
              .map(obj => flatten(obj, {}))
              .map(obj => remap(obj, out_map));
0 голосов
/ 05 декабря 2018

Вы можете попробовать что-то вроде этого

Вы можете достичь с помощью map()

let json = [{id: 123, person: { data: { name: 'John', language: 'Javascript' } }, details: { age: 25 }, has_experience: true },
            {id: 456, person: { data: { name: 'Peter',language: null } }, details: { age: 40 }, has_experience: false},
            {id: 789, person: { data: { name: 'Paul', language: 'Python' } }, details: { age: 30 }, has_experience: null },];

let results = [];

results = json.map(current => {
    let temp = {
        user_id: current.id,
        name: current.person.data.name,
        age: current.details.age,
        
    }
    if (current.has_experience) {
        temp.availablity = current.has_experience
    }  
        if (current.person.data.language) 
        { temp.language = current.person.data.language }
    return temp;
})

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