Ruby club два многомерных ключа в 1 через дату и другие ключевые элементы - PullRequest
0 голосов
/ 05 июля 2018

Я только начал работать над рубиновой Синатрой.

У меня проблема с созданием массива из существующего массива.
У меня есть этот массив, который сгруппирован по дате, и каждый из элементов содержит все записи этого дня.

{
    "2015-05-15": [{
        "minutes": 25,
        "key1": [{
            "some key1": "14",
            "some key": "subject here"
        }],
        "key2": [{
            "some key": "0/0"
        }],
        "key3": [{
            "some key": "5/5"
        }],
        "key4": [{
            "some key": 0.48
        }],
        "key5": [{
            "some key": "0.6"
        }],
        "key6": "2015-05-15"
    }, {
        "minutes": 25,
        "key1": [{
            "some key1": "14",
            "some key": "subject here"
        }],
        "key2": [{
            "some key": "0/0"
        }],
        "key3": [{
            "some key": "5/5"
        }],
        "key4": [{
            "some key": 0.48
        }],
        "key5": [{
            "some key": "0.6"
        }],
        "key6": "2015-05-15"
    }],
    "2015-05-25": [{
        "minutes": 25,
        "key1": [{
            "some key1": "14",
            "some key": "subject here"
        }],
        "key2": [{
            "some key": "0/0"
        }],
        "key3": [{
            "some key": "5/5"
        }],
        "key4": [{
            "some key": 0.48
        }],
        "key5": [{
            "some key": "0.6"
        }],
        "key6": "2015-05-25"
    }],
    "2015-06-10": [{
        "minutes": 25,
        "key1": [{
            "some key1": "14",
            "some key": "subject here"
        }],
        "key2": [{
            "some key": "0/0"
        }],
        "key3": [{
            "some key": "5/5"
        }],
        "key4": [{
            "some key": 0.48
        }],
        "key5": [{
            "some key": "0.6"
        }],
        "key6": "2015-06-10"
    }, {
        "minutes": 25,
        "key1": [{
            "some key1": "14",
            "some key": "subject here"
        }],
        "key2": [{
            "some key": "0/0"
        }],
        "key3": [{
            "some key": "5/5"
        }],
        "key4": [{
            "some key": 0.48
        }],
        "key5": [{
            "some key": "0.6"
        }],
        "key6": "2015-06-10"
    }]
}

Я хочу объединить этот массив так, чтобы все массивы подэлементов располагались с помощью ключей для каждой даты. Например, следующий массив - это то, что я ищу. Здесь все вложенные массивы в дате 2015-05-15 объединены в один ключевой элемент.

 {
    "2015-05-15": [{
        "minutes": 50,
        "key1": [{
            "some key1": "14",
            "some key": "subject here"
        },
        {
            "some key1": "14",
            "some key": "subject here"
        }],
        "key2": [{
            "some key": "0/0"
        },{
            "some key": "0/0"
        }],
        "key3": [{
            "some key": "5/5"
        },
        {
            "some key": "5/5"
        }],
        "key4": [{
            "some key": 0.48
        },
        [{
            "some key": 0.48
        }],
        "key5": [{
            "some key": "0.6"
        },
        {
            "some key": "0.6"
        }],
        "key6": "2015-05-15"
    }],
    "2015-05-25": [{
        "minutes": 50,
        "key1": [{
            "some key1": "14",
            "some key": "subject here"
        },
        {
            "some key1": "14",
            "some key": "subject here"
        }],
        "key2": [{
            "some key": "0/0"
        },{
            "some key": "0/0"
        }],
        "key3": [{
            "some key": "5/5"
        },
        {
            "some key": "5/5"
        }],
        "key4": [{
            "some key": 0.48
        },
        [{
            "some key": 0.48
        }],
        "key5": [{
            "some key": "0.6"
        },
        {
            "some key": "0.6"
        }],
        "key6": "2015-05-25"
    }],
    "2015-06-10": [{
        "minutes": 50,
        "key1": [{
            "some key1": "14",
            "some key": "subject here"
        },
        {
            "some key1": "14",
            "some key": "subject here"
        }],
        "key2": [{
            "some key": "0/0"
        },{
            "some key": "0/0"
        }],
        "key3": [{
            "some key": "5/5"
        },
        {
            "some key": "5/5"
        }],
        "key4": [{
            "some key": 0.48
        },
        [{
            "some key": 0.48
        }],
        "key5": [{
            "some key": "0.6"
        },
        {
            "some key": "0.6"
        }],
        "key6": "2015-06-10"
    }]
}

Я пытался расположить их, используя собственный метод, который я создал.

def self.iterateArray(array)
    result = Hash.new  #{ |h, k| h[k] = [] }
    count =  0
    result[count] = Array.new(7)

    array.each { |key, data|

      result[count]["date"] = key
      data.each { |k, d| 

        k.each { |key_, data1|
          if key_ == 'key1'
            result[count][key_] += data1
          end
          if key_ == 'key2'
            result[count][key_] << data1
          end
          if key_ == 'key3'
            result[count][key_] << data1
          end
          if key_ == 'key4'
            result[count][key_] << data1
          end
          if key_ == 'key5'
            result[count][key_] << data1
          end
          if key_ == 'key6'
            result[count][key_] << data1
          end
        }
      }
      count += 1
    }
    puts "result: #{result}"  
    result
  end

Но каждый раз, когда я пытаюсь запустить этот метод, я получаю странные ошибки, такие как «неявное преобразование строки в целое число» в

result[count]["date"] = key

ранее это создавало такую ​​ошибку на result[count], но затем я инициировал ее с

result[count] = Hash.new { |h, k| h[k] = [] }

И система начала указывать на следующий элемент.

Может кто-нибудь сказать мне, что я делаю не так? Или скажите мне, как я могу справиться с такими проблемами или как создаются собственные массивы .. Любая помощь приветствуется.

Ребята, прошу прощения за добавление туда двух элементов "key2". Это было на самом деле key1 .. to key6 элементов. Я обновил образцы массивов.

Ответы [ 3 ]

0 голосов
/ 05 июля 2018

Код

def convert(h)
  h.each_with_object(Hash.new { |e,k| e[k]={} }) do |(date, v),f|
    v.each { |g| f[date].update(g) { |_,ov,nv|ov.is_a?(Array) ? ov+nv : ov } }
  end
end

Пример

Из-за большого размера и форматирования примера трудно распознать лес за деревьями. Первое, что я сделал, это свел пример с его основной структурой. Я сократил количество ключей (строк даты) с трех до двух и уменьшил количество ключей в каждом хеше. Я также использовал отступы для уточнения структуры. Таким образом я получил следующее.

h = {
  "2015-05-15"=>[
    { "minutes"=>25,
      "key1"=>[{ "some key1"=>"14", "some key"=>"subject here" }],
      "key2"=>[{ "some key"=>"5/5"}],
      "key5"=>"2015-05-15"
    },
    { "minutes"=>25,
      "key1"=>[{ "some key1"=>"14", "some key"=>"subject here" }],
      "key2"=>[{ "some key"=>"5/5" }],
      "key4"=>[{ "some key"=>"0.6" }],
      "key5"=>"2015-05-15"
    }
  ],
  "2015-06-10"=>[
    { "minutes"=>25,
      "key1"=>[{ "some key1"=>"14", "some key"=>"subject here" }],
      "key2"=>[{ "some key"=>"5/5" }],
      "key5"=>"2015-06-10"
    },
    { "minutes"=>25,
      "key1"=>[{ "some key1"=>"14", "some key"=>"subject here" }],
      "key2"=>[{ "some key"=>"5/5"}]
    }
  ]
}

convert(h)
  #=> { "2015-05-15"=>{
  #       "minutes"=>25, 
  #       "key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
  #                {"some key1"=>"14", "some key"=>"subject here"}],
  #       "key2"=>[{"some key"=>"5/5"},
  #            {"some key"=>"5/5"}],
  #       "key5"=>"2015-05-15",
  #       "key4"=>[{"some key"=>"0.6"}]},
  #     "2015-06-10"=>{
  #       "minutes"=>25,
  #       "key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
  #                {"some key1"=>"14", "some key"=>"subject here"}],
  #       "key2"=>[{"some key"=>"5/5"},
  #                {"some key"=>"5/5"}],
  #       "key5"=>"2015-06-10"
  #     }
  #   }

Этот результат немного отличается от того, что было запрошено. Значение каждого ключа строки даты (например, "2015-05-15") должно было быть массивом, содержащим один элемент (хеш). Нет смысла иметь массивы, которые всегда содержат один элемент, поэтому я упростил создание значений хешей строк даты.

Объяснение

Hash.new { |h,k| h[k]={} } приводит к тому, что h[k] устанавливается равным пустому хэшу, когда h не имеет ключа k. Смотрите форму Hash :: new , в которой используется блок.

Я использовал форму Hash # update (a.k.a. merge!) that employs a block to determine the values of keys that are present in both hashes being merged. See the doc for the values of the three block variables, k (common key), ov ("*old value*") and nv` (" new value ")

Код более или менее эквивалентен следующему.

f = {}
h.each do |date, v|
  v.each do |g|
    f[date] = {} unless f.key?(date)
    f[date].update(g) { |_,ov,nv| ov.is_a?(Array) ? ov+nv : ov }
  end
end
f

Если это все еще не ясно, попробуйте запустить этот код с добавлением некоторых операторов puts.

f = {}
h.each do |date, v|
  puts "date=#{date}"
  puts "v=#{v}"
  puts "f=#{f}"
  v.each do |g|
    puts "  f=#{g}"
      if f.key?(date)
        puts "  f has key date=#{date} so f[#{date}] is not set to {}"
      else
        puts "  f does not has key date=#{date} so f[#{date}] is to {}"
      end
    f[date] = {} unless f.key?(date)
    f[date].update(g) { |_,ov,nv| ov.is_a?(Array) ? ov+nv : ov }
    puts "  f[#{date}]= #{f[date]}"
  end
end
f

Это печатает следующее.

date=2015-05-15
v=[{"minutes"=>25, "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}], 
                   "key2"=>[{"some key"=>"5/5"}], "key5"=>"2015-05-15"},
   {"minutes"=>25, "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
                   "key2"=>[{"some key"=>"5/5"}], "key4"=>[{"some key"=>"0.6"}],
                   "key5"=>"2015-05-15"}]
f={}
f={"minutes"=>25, "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
                  "key2"=>[{"some key"=>"5/5"}], "key5"=>"2015-05-15"}
f does not has key date=2015-05-15 so f[2015-05-15] is to {}
f[2015-05-15]= {"minutes"=>25,
                "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
                "key2"=>[{"some key"=>"5/5"}], "key5"=>"2015-05-15"}
f={"minutes"=>25, "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
                  "key2"=>[{"some key"=>"5/5"}],
                  "key4"=>[{"some key"=>"0.6"}],
                  "key5"=>"2015-05-15"}
f has key date=2015-05-15 so f[2015-05-15] is not set to {}
f[2015-05-15]= {"minutes"=>25,
                "key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
                         {"some key1"=>"14", "some key"=>"subject here"}],
                "key2"=>[{"some key"=>"5/5"},
                         {"some key"=>"5/5"}],
                "key5"=>"2015-05-15",
                "key4"=>[{"some key"=>"0.6"}]}

date=2015-06-10
v=[{"minutes"=>25,
    "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
    "key2"=>[{"some key"=>"5/5"}],
    "key5"=>"2015-06-10"},
       {"minutes"=>25,
        "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
        "key2"=>[{"some key"=>"5/5"}]}]
f={"2015-05-15"=>{"minutes"=>25,
                  "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}, 
                          {"some key1"=>"14", "some key"=>"subject here"}],
                  "key2"=>[{"some key"=>"5/5"},
                          {"some key"=>"5/5"}],
                  "key5"=>"2015-05-15", 
                  "key4"=>[{"some key"=>"0.6"}]}}
f={"minutes"=>25,
   "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
   "key2"=>[{"some key"=>"5/5"}],
   "key5"=>"2015-06-10"}
f does not has key date=2015-06-10 so f[2015-06-10] is to {}

f[2015-06-10]= {"minutes"=>25,
                "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
                "key2"=>[{"some key"=>"5/5"}], "key5"=>"2015-06-10"}
f={"minutes"=>25,
   "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
   "key2"=>[{"some key"=>"5/5"}]}
f has key date=2015-06-10 so f[2015-06-10] is not set to {}
f[2015-06-10]= {"minutes"=>25,
                "key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
                         {"some key1"=>"14", "some key"=>"subject here"}], 
                "key2"=>[{"some key"=>"5/5"}, {"some key"=>"5/5"}], 
                "key5"=>"2015-06-10"}
0 голосов
/ 06 июля 2018

Я достиг своего ответа, используя этот метод, который я создал. Здесь я удалил поле «дата», поскольку оно повторялось.

 def self.iterateArray(array)
    response = []
    array.each { |key, data|
      result = Hash.new { |h, k| h[k] = [] }

      result["date"] = key
      result["minutes"] =0
      result["key1"] =[]
      result["key2"] =[]
      result["key3"] =[]
      result["key4"] =[]
      result["key5"] =[]
      data.each { |k, d| 

        k.each { |key1, data1|
          if key1 == "minutes"
            result[key1] += data1
          elsif key1 != "date"
            result[key1] << data1[0]
          end
        }
      }
      response << result
    }
    response
  end

Но мне все еще не нравится, как нам нужно объявлять все переменные в массиве перед добавлением значения к ним. Есть ли какое-то решение для этого?

0 голосов
/ 05 июля 2018

проблем в вашем вопросе

  • У вас есть ключ "key2" дважды в каждом хеше (как вход, так и выход). Таким образом, последний переопределит значения первого присваивания. Из примера с инженерамнки: {key2: 1, key2: 2} #=> {key2: 2}

  • Вы не объяснили полную логику для преобразования вашего ввода в вывод.

  • Не знаю, нужно ли готовить полученный хеш с учетом типа значений, например Integer, Array и т. Д., Или он специфичен для ключа, т. Е. Всегда суммировать значения для ключа "minutes" без проверка его типа.

Решение

Итак, хотя я не уверен в логике вашего ожидаемого вывода, я смог преобразовать в него ваш исходный массив:

Введите:

input = {
  "2015-05-15" => [{
    "minutes" => 25,
    "key1" => [{
        "some key1" => "14",
        "some key" => "subject here"
    }],
    "key2" => [{
        "some key" => "5/5"
    }],
    "key3" => [{
        "some key" => 0.48
    }],
    "key4" => [{
        "some key" => "0.6"
    }],
    "key5" => "2015-05-15"
}, {
    "minutes" => 25,
    "key1" => [{
        "some key1" => "14",
        "some key" => "subject here"
    }],
    "key2" => [{
        "some key" => "5/5"
    }],
    "key3" => [{
        "some key" => 0.48
    }],
    "key4" => [{
        "some key" => "0.6"
    }],
    "key5" => "2015-05-15"
}],
"2015-05-25" => [{
    "minutes" => 25,
    "key1" => [{
        "some key1" => "14",
        "some key" => "subject here"
    }],
    "key2" => [{
        "some key" => "5/5"
    }],
    "key3" => [{
        "some key" => 0.48
    }],
    "key4" => [{
        "some key" => "0.6"
    }],
    "key5" => "2015-05-25"
}],
"2015-06-10" => [{
    "minutes" => 25,
    "key1" => [{
        "some key1" => "14",
        "some key" => "subject here"
    }],
    "key2" => [{
        "some key" => "5/5"
    }],
    "key3" => [{
        "some key" => 0.48
    }],
    "key4" => [{
        "some key" => "0.6"
    }],
    "key5" => "2015-06-10"
}, {
    "minutes" => 25,
    "key1" => [{
        "some key1" => "14",
        "some key" => "subject here"
    }],
    "key2" => [{
        "some key" => "5/5"
    }],
    "key3" => [{
        "some key" => 0.48
    }],
    "key4" => [{
        "some key" => "0.6"
    }],
    "key5" => "2015-06-10"
  }]
}

Процедура:

output = {}

input.each do |date, ary|
  keys = ary.map(&:keys).flatten.uniq    # Returns all the keys in all the hash elements for given date

  hash = {}

  keys.each do |key|
    if ary.all? { |e| e[key].is_a?(Integer) }
      hash[key] = ary.inject(0) { |sum, h| sum + h[key].to_i }    # Assuming you want to sum up values for keys with integer values
    elsif ary.all? { |e| e[key].is_a?(Array) }
      hash[key] = ary.inject([]) { |sum, h| sum + h[key] }        # Assuming you need `+` operation on the array values too 
    elsif ary.all? { |e| e[key].is_a?(String) }
      hash[key] = ary[0][key]                                     # Assuming string values are same in all the elements of array
    else
      raise "Invalid type for value of key: #{key}"
    end
  end
  output[date] = [hash]     # I don't know why are we putting it in array as it will always be one element only. You could do: `output[date] = hash`
end

Выход:

output
 => {"2015-05-15"=>[{
       "minutes"=>50,
       "key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
                {"some key1"=>"14", "some key"=>"subject here"}],
       "key2"=>[{"some key"=>"5/5"}, {"some key"=>"5/5"}],
       "key3"=>[{"some key"=>0.48}, {"some key"=>0.48}],
       "key4"=>[{"some key"=>"0.6"}, {"some key"=>"0.6"}],
       "key5"=>"2015-05-15"}],
     "2015-05-25"=>[{
       "minutes"=>25,
       "key1"=>[{"some key1"=>"14", "some key"=>"subject here"}],
       "key2"=>[{"some key"=>"5/5"}],
       "key3"=>[{"some key"=>0.48}],
       "key4"=>[{"some key"=>"0.6"}],
       "key5"=>"2015-05-25"
     }],
     "2015-06-10"=>[{
       "minutes"=>50,
       "key1"=>[{"some key1"=>"14", "some key"=>"subject here"},
                {"some key1"=>"14", "some key"=>"subject here"}],
       "key2"=>[{"some key"=>"5/5"}, {"some key"=>"5/5"}],
       "key3"=>[{"some key"=>0.48}, {"some key"=>0.48}],
       "key4"=>[{"some key"=>"0.6"}, {"some key"=>"0.6"}],
       "key5"=>"2015-06-10"
     }]
   }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...