Группировать массив по вложенному массиву - PullRequest
0 голосов
/ 02 апреля 2012

У меня есть массив в этом формате:

[ 
  { 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 ]

2 голосов
/ 02 апреля 2012

Вот вариант решения @ 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 голос
/ 02 апреля 2012

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

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!

Я уверен, что есть лучшие подходы: -)

0 голосов
/ 10 апреля 2012

Расширение ответа @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

Возможно, вам следует разделить это на отдельные методы, но вы поймете идею.

0 голосов
/ 02 апреля 2012

Вам нужно посмотреть Map Method для массива.Вам необходимо переназначить массив и выполнить итерацию по нему, чтобы извлечь нужные данные, используя указанную выше логику «группировки».

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