按嵌套数组分组数组

时间:2012-04-02 13:33:54

标签: ruby grouping

我有一个这种格式的数组:

[ 
  { day: 1
    intervals: [
      {
        from: 900,
        to: 1200
      }
    ]
  },
  { day: 2
    intervals: [
      {
        from: 900,
        to: 1200
      }
    ]
  },
  { day: 3
    intervals: [
      {
        from: 900,
        to: 1200
      }
    ]
  },
  { day: 4
    intervals: [
      {
        from: 900,
        to: 1200
      }
    ]
  },
  { day: 5
    intervals: [
      {
        from: 900,
        to: 1200
      }
    ]
  },
  { day: 6
    intervals: [
      {
        from: 900,
        to: 1200
      },
      {
        from: 1300,
        to: 2200
      }
    ]
  },
  { day: 7
    intervals: [
      {
        from: 900,
        to: 1200
      },
      {
        from: 1300,
        to: 2200
      }
    ]
  }
]

我不想这样分组:

[ 
  { day: 1-5
    intervals: [
      {
        from: 900,
        to: 1200
      }
    ]
  },
  { day: 6-7
    intervals: [
      {
        from: 900,
        to: 1200
      },
      {
        from: 1300,
        to: 2200
      }
    ]
  }
]

标准:

  • 如果间隔相同,则仅限组。
  • 如果匹配按时间顺序排列,则只有组,即1-5或1-3,而不是1-2-5。

如何实现这一目标?

4 个答案:

答案 0 :(得分:2)

这是@ joelparkerhenderson的解决方案的变体,它试图更接近你的要求重新格式化输出等。

output = []

grouped = input.group_by do |x|
  x[:intervals]
end

grouped.each_pair do |k, v|
  days = v.map {|day| day[:day]}
  if days.each_cons(2).all? { |d1, d2| d1.next == d2 }
    output << {
      :days => days.values_at(0,-1).join('-'),
      :intervals => k
    }
  end
end

puts output

答案 1 :(得分:1)

这会产生所需的输出:

by_interval = data.inject({}) do | a, e |
  i = e[:intervals]
  a[i] ||= []
  a[i] << e[:day].to_i
  a
end

result = by_interval.map do | interval, days |
  slices = days.sort.inject([]) do | a, e |
    a << [] if a == [] || a.last.last != e - 1
    a.last << e
    a
  end
  slices.map do | slice |
      {:day => "#{slice.first}-#{slice.last}", :intervals => interval }
  end
end
result.flatten!

我确信有更好的方法: - )

答案 2 :(得分:0)

您需要查看Map Method数组。您需要重新映射数组并对其进行迭代,以使用上面的“分组”逻辑提取所需的数据。

答案 3 :(得分:0)

扩展@Michael Kohl的回答

output = []

grouped = schedules.as_json.group_by do |x|
  x['intervals']
end

grouped.each_pair do |k, v|
  days = v.map {|day| day['day']}
  grouped_days = days.inject([[]]) do |grouped, num|
    if grouped.last.count == 0 or grouped.last.last == num - 1
      grouped.last << num
    else
      grouped << [ num ]
    end
    grouped
  end

  grouped_days.each do |d|
    output << {
      heading: d.values_at(0, -1).uniq.join('-'),
      interval: k
    }
  end
end

output

你应该把它分成不同的方法,但你明白了。