Массив объектов (JSON) в один объект (датафрейм) - PullRequest
0 голосов
/ 15 декабря 2018

В приведенном ниже коде я создаю «фальшивый» фрейм данных из ответа JSON для целей Python-подобных манипуляций с данными.

Существует ли менее подробный способ сделать это, чем то, что опубликовано ниже?

По сути, мне нужно поместить массив объектов в один объект.Все объекты имеют одинаковую структуру.

<script>
    //~ request API for data
    function get_data(callback){
        $.ajax({type:"GET", 
                url: "{% url 'explorer_api:list_activities' %}",
                //~ success: function(data){
                    //~ console.log(data[1])},
                success: callback,
                headers: {'X-CSRFToken': '{{ csrf_token }}'},

        });
    }

    //~ get data and process it
    get_data(function(data) {

        //create dataframe
        function create_dataframe() {
            var activities = data;                  
            var df = {
                number: [],
                athlete: [],
                start_date: [],
                name: [],   
                country: [],
                link: [],
                segment_efforts:[],
                distance: [],
                average_speed: [],
            };

            for (i in activities) {
                df.number.push(activities[i].number);
                df.athlete.push(activities[i].athlete);
                df.start_date.push(activities[i].start_date);
                df.name.push(activities[i].name);
                df.country.push(activities[i].country);
                df.link.push(activities[i].link);
                df.segment_efforts.push(activities[i].segment_efforts);
                df.distance.push(activities[i].distance);
                df.average_speed.push(activities[i].average_speed);
            };
            return df;
        };
        df = create_dataframe()
        console.log(df);
    }); 
</script>

Ответы [ 4 ]

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

Это функциональный (ES6) подход:

data.reduce((a,c) => { Object.keys(c).map(k => a[k] = a[k] ? [...a[k],c[k]] : [c[k]]); return a; }, {})

Хотя я бы не стал ставить на повышение производительности по сравнению с императивным подходом в случае JavaScript.

[Обновление]

Вот императив, который является «наиболее близким» к описанному выше функционалу:

result = { }
for(var e of DATA){
   for(var p in e){
      if(result[p]) { result[p].push(e[p]) } else { result[p] = [e[p]] }
   }
}

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

Но, как я подозревал и как я уже заметил в некоторых сценариях, функциональная сторона JavaScript на самом деле не разработана с точки зрения производительности.

Но я хотел увидеть себя, поэтому я протестировал два приведенных выше фрагмента здесь: https://jsperf.com/ao-to-oa-imp-func/1

И результаты для меня более чем убедительны: функциональный код работает на 93% медленнеечем в моем Chrome, и на 99% медленнее в Firefox.

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

Вы можете использовать Object.entries для перебора ключей в объекте.Пример:

var activities = [{ number: 1, test: 2 }, { number: 2, test: 3 }]

var df = {}

for (var activity of activities) {
  for (var [key, value] of Object.entries(activity)) {
    if (!df[key]) df[key] = []
    df[key].push(value)
  }
}
df // { number: [1,2], test: [2,3] }
0 голосов
/ 15 декабря 2018

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

const arr = [{id: 0, value: 'foo'},{id: 1, value: 'bar'},{id: 2, value: 'baz'}];

const obj = arr.reduce((initial, value, index) => {
  const keys = Object.keys(value);
  keys.forEach(key => {
    if(!initial[key]) initial[key] = [value[key]];
    else initial[key].push(value[key]);
  });
  return initial;
}, {});

console.log(obj)

Что касается многословности, это мало что меняет, но я думаю, что это лучшая и более динамичная реализация, чем та, что в вашем вопросе.

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

Вы можете использовать другой цикл for-in для циклического просмотра свойств вашего объекта вместо записи каждой строки.

for(i in activities) {
    for(var prop in df) {
        df[prop].push(activities[i][prop]);
    }
}

Я также рекомендовал бы использовать традиционный цикл for или другой метод, например .forEach ().перебрать activities, так как for-in не рекомендуется для массивов .

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