Фильтрация файлов JSON и поиск значений

#javascript #json #reactjs

#javascript #json #reactjs

Вопрос:

Я получаю файл JSON, который содержит данные о погоде в ряде городов. Вот пример данных.

 const weatherArray = [{
            "Date": '5-1-19',
            "Location": 'New York',
            "Rainfall": 4},
                                     {
            "Date": '5-1-19',
            "Location": 'Miami',
            "Rainfall": 8},
                                     {
            "Date": '5-1-20',
            "Location": 'New York',
            "Rainfall": 9},
                                     {
            "Date": '5-1-20',
            "Location": 'Miami',
            "Rainfall": 2},
                                     {
            "Date": '5-1-21',
            "Location": 'New York',
            "Rainfall": 10},
                                     {
            "Date": '5-1-21',
            "Location": 'Chicago',
            "Rainfall": 9},
                                    ]
  

Что мне нужно сделать, это отфильтровать эти данные и сохранить максимальное количество осадков для каждого города в массиве. Я полагаю, что моя функция завершена, но filterData возвращает массив из 6 неизвестных объектов.

 filterData = (inputArray) => {
    let rain = inputArray.map(obj => rain.find(o => o.Location === obj.Location amp;amp; obj.Rainfall > o.Rainfall) || rain.find(o => o.Location !== obj.Location));
    return rain;
    }
  

Я хотел бы, чтобы выходной массив содержал весь объект, связанный с максимальным количеством осадков для каждого города в файле JSON.

 rain = [{
        "Date": '5-1-19',
        "Location": 'Miami',
        "Rainfall": 8},
{
        "Date": '5-1-21',
        "Location": 'New York',
        "Rainfall": 10},
{
        "Date": '5-1-21',
        "Location": 'Chicago',
        "Rainfall": 9},
]
  

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

1. пожалуйста, добавьте желаемый результат.

2. у вас разные даты?

Ответ №1:

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

 const
    weatherArray = [{ Date: "5-1-19", Location: "New York", Rainfall: 4 }, { Date: "5-1-19", Location: "Miami", Rainfall: 8 }, { Date: "5-1-20", Location: "New York", Rainfall: 9 }, { Date: "5-1-20", Location: "Miami", Rainfall: 2 }, { Date: "5-1-21", Location: "New York", Rainfall: 10 }, { Date: "5-1-21", Location: "Chicago", Rainfall: 9 }],
    filterData = (inputArray) => {
        return Array.from(
            inputArray.reduce((m, { Location, Rainfall }) =>
                m.set(Location, Math.max(m.get(Location) || 0, Rainfall)), new Map),
            ([Location, Rainfall]) => ({ Location, Rainfall })
        );
    };
  
console.log(filterData(weatherArray));  
 .as-console-wrapper { max-height: 100% !important; top: 0; }  

С датой.

 const
    weatherArray = [{ Date: "5-1-19", Location: "New York", Rainfall: 4 }, { Date: "5-1-19", Location: "Miami", Rainfall: 8 }, { Date: "5-1-20", Location: "New York", Rainfall: 9 }, { Date: "5-1-20", Location: "Miami", Rainfall: 2 }, { Date: "5-1-21", Location: "New York", Rainfall: 10 }, { Date: "5-1-21", Location: "Chicago", Rainfall: 9 }],
    filterData = (inputArray) => {
        return Array.from(inputArray
            .reduce((m, o) => {
                var temp = m.get(o.Location)
                return temp amp;amp; temp.Rainfall > o.Rainfall
                    ? m
                    : m.set(o.Location, o);
            }, new Map)
            .values()
        );
    };
  
console.log(filterData(weatherArray));  
 .as-console-wrapper { max-height: 100% !important; top: 0; }  

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

1. приятно, но это решение не сохраняет дату последнего выпавшего дождя

2. @jsdeveloper, это требуется?

3. может быть, и нет, но это было в желаемом результате, опубликованном выше

Ответ №2:

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

 weatherArray.reduce((accumulator, current) => {
    // check if given city is already in reducing array result
    let cityExists = accumulator.findIndex(k => k.Location === current.Location)
    if(cityExists > -1) {
        // there is a city in resulting array, check values and perhaps update
        if(accumulator[cityExists].Rainfall < current.Rainfall) {
            accumulator[cityExists].Rainfall = current.Rainfall
            accumulator[cityExists].Date = current.Date
        }
    } else {
        // no such city, just add it
        accumulator.push(current)
    }
    return accumulator
}, []) // start with an empty array
  

Ответ №3:

Лично я бы разбил задачу на несколько подзадач (вместо того, чтобы пытаться выполнить все это в одной строке), вот так:

задача 1: получить все уникальные местоположения

задача 2: для определенного местоположения найдите максимальное количество осадков

задача 3: объединить уникальные местоположения с соответствующим максимальным количеством осадков

Если вы напишете функцию для каждого из них, я полагаю, вы сможете решить это самостоятельно.

Ответ №4:

Просто используйте reduce :

 const weatherArray = [{
    "Date": '5-1-19',
    "Location": 'New York',
    "Rainfall": 4
  },
  {
    "Date": '5-1-19',
    "Location": 'Miami',
    "Rainfall": 8
  },
  {
    "Date": '5-1-20',
    "Location": 'New York',
    "Rainfall": 9
  },
  {
    "Date": '5-1-20',
    "Location": 'Miami',
    "Rainfall": 2
  },
  {
    "Date": '5-1-21',
    "Location": 'New York',
    "Rainfall": 10
  },
  {
    "Date": '5-1-21',
    "Location": 'Chicago',
    "Rainfall": 9
  }
];

const rain = weatherArray.reduce((acc, { Date, Location, Rainfall }) => {
  if (acc.some(e => e.Location == Location)) { 
    if (acc.find(e => e.Location == Location).Rainfall > Rainfall) {
      return acc;
    } 
    acc.push({ Date, Location, Rainfall});
    acc.splice(acc.findIndex(e => e.Location == Location), 1);
    return acc;
  }
  acc.push({ Date, Location, Rainfall });
  return acc;
}, []);

console.log(rain);  
 .as-console-wrapper { max-height: 100% !important; top: auto; }  

Ответ №5:

Что я бы вам посоветовал, так это начать разбивать ваше функциональное программирование на более понятные функции (для вас), прежде чем пытаться создавать однострочники.

Существует множество алгоритмов, которые вы можете использовать для своего решения:

  • Вы могли бы получить массив результатов для каждого города, отсортировать его и получить самый большой (вероятно, это можно сделать чище с помощью Array.reduce). Очень близко к решению @Maciej Kwas.
  • Вы могли бы создать объект для использования в качестве словаря, где при первом поиске города вы сохраняете его название и значение количества осадков, и для каждого элемента в итерации проверяете, есть ли город уже в вашем объекте, и обновляете значение количества осадков, если оно больше.
  • Вы можете использовать рекурсию, чтобы сгруппировать ваши значения по городам, а затем выполнить итерацию по ним.

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

Поэтому моим рекомендуемым решением был бы вариант 2, и это мог бы быть код:

 const rain = {};
weatherArray.forEach(weather => {
    const currentCity = weather.Location;
    if (rain.hasOwnProperty(currentCity) amp;amp; rain[currentCity].Rainfall < weather.Rainfall) {
        rain[currentCity] = {Rainfall: weather.Rainfall, Date: weather.Date };
    } else {
        rain[currentCity] = weather;
    };)

  

rain будет объектом значений:

 {
'Miami': {"Date": '5-1-19',
        "Rainfall": 8},
'New York': {
        "Date": '5-1-21',
        "Rainfall": 10},
'Chicago': {
        "Date": '5-1-21',
        "Rainfall": 9},
}
  

Может быть легко преобразован в массив, если это ваш конечный результат.
Если доступен ES2016, вы также можете использовать новые итерации карты.