Ruby gruppe hashes af værdien af nøgle

Jeg har en array, som er output fra en map/reduce metode, der udføres af MongoDB, det ser noget som dette:

[{"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>299.0}, 
{"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>244.0}, 
{"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>1.0, "count"=>204.0}, 
{"minute"=>45.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>510.0}, 
{"minute"=>45.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>437.0}, 
{"minute"=>0.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>469.0}, 
{"minute"=>0.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>477.0}, 
{"minute"=>15.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>481.0}, 
{"minute"=>15.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>401.0}, 
{"minute"=>30.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>468.0}, 
{"minute"=>30.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>448.0}, 
{"minute"=>45.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>0.0, "count"=>485.0}, 
{"minute"=>45.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "type"=>10.0, "count"=>518.0}] 

Vil du bemærke, at der er tre forskellige værdier for type, i dette tilfælde 0, 1, og 2, nu ønsker at gøre, er gruppen af dette array af hashes af værdien sin type nøgle, så for eksempel denne række ville ende ud med at ligne:

{
  :type_0 => [
    {"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>299.0}, 
    {"minute"=>45.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>510.0}, 
    {"minute"=>0.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>469.0}, 
    {"minute"=>15.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>481.0}, 
    {"minute"=>30.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>468.0}, 
    {"minute"=>45.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>485.0}
  ],

  :type_1 => [
    {"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>204.0}
  ],

  :type_10 => [
    {"minute"=>30.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>244.0}, 
    {"minute"=>45.0, "hour"=>15.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>437.0},
    {"minute"=>0.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>477.0}, 
    {"minute"=>15.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>401.0}, 
    {"minute"=>30.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>448.0}, 
    {"minute"=>45.0, "hour"=>16.0, "date"=>5.0, "month"=>9.0, "year"=>2011.0, "count"=>518.0}
  ]
} 

, så jeg ved, at disse eksempel arrays er virkelig stor, men jeg tror, det kan være et mere simpelt problem, end jeg gør det ud til at være

Så dybest set, hver vifte af hashes vil blive grupperet efter værdien af sin type – tasten, og derefter tilbage som en hash med et array for hver type, nogen hjælp overhovedet ville være virkelig virkelig hjælpsom, selv blot nogle nyttige tips vil være meget værdsat.

OriginalForfatteren JP Silvashy | 2011-10-06

4 svar

  1. 31
    array.group_by {|x| x['type']}

    eller hvis du vil have symbolet vigtigste ting, du kan endda

    array.group_by {|x| "type_#{x['type']}".to_sym}

    Jeg tror, at dette bedst udtrykker “Så dybest set, hver vifte af hashes ville være grupperet efter værdien af sin type nøgle, og derefter tilbage som en hash med et array for hver type“, selv om det efterlader :type centrale alene i output-hashes.

    det betyder ikke producere output i spørgsmålet, og ikke arbejde i Ruby 1.8
    Denne gruppe vil, men det betyder ikke slette ‘type’ svar. Jeg har ikke noget imod det, da det er simpelt, men det gør ikke besvare spørgsmålet, tbh.

    OriginalForfatteren Tapio Saarinen

  2. 2

    Noget som dette måske?

    mangled = a.group_by { |h| h['type'].to_i }.each_with_object({ }) do |(k,v), memo|
        tk = ('type_' + k.to_s).to_sym
        memo[tk] = v.map { |h| h = h.dup; h.delete('type'); h }
    end

    Eller hvis du ikke bekymrer sig om at bevare de oprindelige data:

    mangled = a.group_by { |h| h['type'].to_i }.each_with_object({ }) do |(k,v), memo|
        tk = ('type_' + k.to_s).to_sym
        memo[tk] = v.map { |h| h.delete('type'); h } # Drop the h.dup in here
    end

    OriginalForfatteren mu is too short

  3. 2
    by_type = {}
    
    a.each do |h|
       type = h.delete("type").to_s
       # type = ("type_" + type ).to_sym
    
       by_type[ type ] ||= []
       by_type[ type ] << h      # note: h is modified, without "type" key
    
    end

    Bemærk: lidt forskellige hash-nøgler her, jeg brugte den type værdier direkte som den centrale

    hvis du er nødt til at have hash-nøgler, som i dit eksempel, kan du tilføje den linje, der er kommenteret ud.


    P. S.: jeg har lige set Tapio ‘ s løsning-det er meget flot og kort! Bemærk, at det kun virker med Ruby >= 1.9

    hvorfor ikke bare a.group_by {|x| x['type']} ?
    I og med at det ikke fjerne den ‘type’ nøgle? Jeg tror ikke, der virkelig ville noget, ville det?
    i hans eksempel, blev han forventer, at den “type” nøglen er fjernet fra hashes undervejs… Ja, jeg er enig, gør ikke rigtig noget .. group_by() er ny og lækker, tak! +1

    OriginalForfatteren Tilo

  4. 1

    group_by samler en utallige i sæt, grupperet efter, resultatet af en blok. Du er ikke begrænset til blot at få nøgle værdi i dette felt, så hvis du gerne vil udelade 'type' i disse sæt, kan du gøre det, ligesom i:

    array.group_by {|x| "type_#{x.delete('type').to_i}".to_sym}

    Dette vil resultere præcis i, hvad du spurgte om.

    Avanceret: Det går lidt ud af omfanget af spørgsmål, men hvis du ønsker at bevare den oprindelige array, skal du duplikere hvert objekt inde i det. Dette vil gøre det trick:

    array.map(&:dup).group_by {|x| "type_#{x.delete('type').to_i}".to_sym}

    OriginalForfatteren Claudio Floreani

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *