【问题标题】:Prevent Nil Values in Transformed Array防止转换数组中的 Nil 值
【发布时间】:2019-02-20 09:13:23
【问题描述】:

删除nilsquite simple,但是,我想知道:

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 的 recommendation 先到 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]]}]

我尝试使用哈希而不是 @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>

【问题讨论】:

    标签: arrays json ruby ruby-on-rails-4 highcharts


    【解决方案1】:

    我会采用更多的 reduce 方法,因为您正在获取一个列表并将其归结为另一个对象。 each_with_object 执行 reduce 但在每个循环中隐式返回 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
    

    旁注:地图通常更多用于转换或等效更改,这就是我认为这里感觉不对的原因。

    【讨论】:

    • 嗯,这是 each_with_object,与每个都非常不同。 each 只是一个循环迭代器, each_with_object 减少列表。我不明白你的意思,因为如果你使用 reduce 方法,当你遇到你不想要的东西时不要推送到数组。
    • 好的,我 100% 认为这是正确的方法,所以如果您遇到任何问题,请发帖,如果可以,我会提供帮助
    • 对不起,我是红宝石菜鸟。这会输出一个哈希,但最后我需要它在一个排序数组中。我应该只在视图中使用&lt;%=@cars.values%&gt; 还是有更好的选择?
    • 嘿,没问题,这就是我会做的。哈希使得通过 id 查找正确映射变得方便,然后它是数组格式是一个视图问题,所以要么在控制器中设置 @cars = cars.values 要么只是访问你正在做的方式。
    • 随选角更新
    【解决方案2】:

    我建议按 id 分组,然后创建一个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([]) 作为对象传递允许将元素插入到默认数组中。

    最终将哈希映射到所需的键。

    【讨论】:

    • 从快速基准测试来看,这似乎是迄今为止提供的最有效的选项。但是,我最后确实需要一个数组。
    • @webaholik,在看到更新后的问题后进行了编辑。也许这会给出所需的结果。
    【解决方案3】:

    您的代码之所以如此,是因为 array[8] = x 在数组的第 8 位插入了 x,而 ruby​​ 用 nil 填充最多 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 的解决方案几乎相同。

    【讨论】:

    • @cars = Array.new 更新为@cars = Hash.new 确实提供了没有nils 的数据,但是,我最终确实需要array
    猜你喜欢
    • 1970-01-01
    • 2020-08-15
    • 2022-12-10
    • 1970-01-01
    • 2017-12-06
    • 1970-01-01
    • 2020-06-19
    • 2022-09-24
    • 1970-01-01
    相关资源
    最近更新 更多