Предотвратить нулевые значения в преобразованном массиве - PullRequest
0 голосов
/ 16 сентября 2018

Удаление nils - это довольно просто , однако, я хотел бы знать:

1) Что я делаю не так, почему результат моего массива ниже nils?

2) Как я могу ПРЕДОТВРАТИТЬ nils от добавления в мой массив, вместо того, чтобы удалять их после факта.

@cars = Array.new
plucked_array = [
    [8, "Chevy", "Camaro", 20],
    [9, "Ford", "Mustang", 55],
    [9, "Ford", "Fusion", 150]
]
plucked_array.
    each { |id, make, model, model_count|
      @cars[id] ||= {name: make, id: make, data: []}
      @cars[id][:data].push([model, model_count])
    }
puts @cars.inspect
#=>[nil, nil, nil, nil, nil, nil, nil, nil, {:name=>"Chevy", :id=>"Chevy", :data=>[["Camaro", 20]]}, {:name=>"Ford", :id=>"Ford", :data=>[["Mustang", 55], ["Fusion", 150]]}]

puts @cars.compact.inspect
#=>[{:name=>"Chevy", :id=>"Chevy", :data=>[["Camaro", 20]]}, {:name=>"Ford", :id=>"Ford", :data=>[["Mustang", 55], ["Fusion", 150]]}]
# This gives the result I'm looking for, 
# just wondering how to best get transformed array without the post-cleanup.

Я также попытался сначала рекомендация @ theTinMan до select, затем map, но у меня были те же результаты:

plucked_array.select { |id, make, model, model_count|
  @cars[id] = {'name' => make, 'id' => make, 'data' => []}
}.map { |id, make, model, model_count|
  @cars[id]['data'].push([model, model_count])
}
puts @cars.inspect
#=>[nil, nil, nil, nil, nil, nil, nil, nil, {:name=>"Chevy", :id=>"Chevy", :data=>[["Camaro", 20]]}, {:name=>"Ford", :id=>"Ford", :data=>[["Mustang", 55], ["Fusion", 150]]}]

Я пытался с частичным успехом использовать Hash вместо массива для @cars. Это предотвратило работу nils, но моя конечная цель - построить ниже «Drilldown: series []», представляющий собой массив хэшей:

// Create the chart
Highcharts.chart('container', {
    chart: {
        type: 'column'
    },
    title: {
        text: 'Imaginary Car Stats'
    },
    subtitle: {
        text: 'Click the columns to view models.'
    },
    xAxis: {
        type: 'category'
    },
    yAxis: {
        title: {
            text: 'Total car count'
        }
    },
    legend: {
        enabled: false
    },
    plotOptions: {
        series: {
            borderWidth: 0,
            dataLabels: {
                enabled: true,
                format: '{point.y}'
            }
        }
    },
    tooltip: {
        headerFormat: '<span style="font-size:11px">{series.name}</span><br>',
        pointFormat: '<span style="color:{point.color}">{point.name}</span>: <b>{point.y:.2f}%</b> of total<br/>'
    },
    /*I have separate `pluck` query for this top-level series:*/
    "series": [
        {
            "name": "Cars",
            "colorByPoint": true,
            "data": [
                {
                    "name": "Ford",
                    "y": 205,
                    "drilldown": "Ford"
                },
                {
                    "name": "Chevy",
                    "y": 20,
                    "drilldown": "Chevy"
                },
                {
                    "name": "Other",
                    "y": 16,
                    "drilldown": null
                }
            ]
        }
    ],
    "drilldown": {
        /*This is the array of hashes I'm attempting to create:*/
        "series": [
            {
                "name": "Ford",
                "id": "Ford",
                "data": [
                    [
                        "Fusion",
                        150
                    ],
                    [
                        "Mustang",
                        55
                    ]
                ]
            },
            {
                "name": "Chevy",
                "id": "Chevy",
                "data": [
                    [
                        "Camaro",
                        20
                    ]
                ]
            }
        ]
    }
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/data.js"></script>
<script src="https://code.highcharts.com/modules/drilldown.js"></script>

<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>

Ответы [ 3 ]

0 голосов
/ 16 сентября 2018

Я предлагаю группировать по идентификатору, а затем создать hash:

plucked_array.group_by(&:first).transform_values{ |v| v.map{ |id, make, model, model_count|  {name: make, id: make, data: [model, model_count]} }}

#  {8=>[{:name=>"Chevy", :id=>"Chevy", :data=>["Camaro ls", 20]}], 
#   9=>[{:name=>"Ford", :id=>"Ford", :data=>["Mustang", 55]}, {:name=>"Ford", :id=>"Ford", :data=>["Fusion", 150]}]}
#  }


Редактировать - обновление соответствует редактированию исходного вопроса (получить серию данных для Highcharts)

Это должно вернуть требуемый результат:

plucked_array.map.with_object(Hash.new([])) { |(id, make, model, model_count), h|
  h[make] += [[model, model_count]] }.map { |k, v| {name: k, id: k, data: v }}

#=> [{:name=>"Chevy", :id=>"Chevy", :data=>[["Camaro", 20]]}, {:name=>"Ford", :id=>"Ford", :data=>[["Mustang", 55], ["Fusion", 150]]}]

Первая часть создает такой хеш, как этот.

#=> {"Chevy"=>[["Camaro", 20]], "Ford"=>[["Mustang", 55], ["Fusion", 150]]}

Передача Hash.new([]) в качестве объекта позволяет вставлять элементы в массив по умолчанию.

Наконец, хэш сопоставляется с необходимыми ключами.

0 голосов
/ 16 сентября 2018

Причина, по которой ваш код ведет себя так, как он делает, заключается в том, что array[8] = x вставляет x в позицию 8 в массиве, а ruby ​​заполняет пробелы до 8 нулями.

a = []
a[7] = 4
a == [nil, nil, nil, nil, nil, nil, nil, 4]

Вынужно @cars, чтобы быть хешем, а не массивом

Я думаю, что это сделает то, что вы пытаетесь сделать:

plucked_array = [
    [8, "Chevy", "Camaro", 20],
    [9, "Ford", "Mustang", 55],
    [9, "Ford", "Fusion", 150]
]

cars = plucked_array.each_with_object({}) do |(id, make, model, count), cars|
  cars[id] ||= {id: id, make: make, data: []}
  cars[id][:data] << [model, count]
end

p cars.values

Что на самом деле почти идентично решению @ Austio.

0 голосов
/ 16 сентября 2018

Я бы пошел на более редкий подход, потому что вы берете список и сводите его к другому объекту.each_with_object делает приращение, но неявно возвращает obj (в данном случае автомобили) в каждом цикле

new_list = plucked_array.each_with_object({}) do |(id, make, model, model_count), cars|
  # return before mutating cars hash if the car info is invalid
  cars[id] ||= {name: make, id: make, data: []}
  cars[id][:data].push([model, model_count])
end

# Then in your controller to handle the usage as an array
@cars = new_list.values

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

...