Модуль body-parser
обрабатывает только сообщения JSON и urlencoded, а не multipart (это было бы так, если вы загружаете файлы).
Для multipart вы 'd нужно использовать что-то вроде connect-busboy
или multer
или connect-multiparty
(многопартийное / грозное - это то, что первоначально использовалось в экспресс-курьерское промежуточное ПО). Кроме того, FWIW, я работаю над еще более высоким уровнем над буксиром под названием reformed
. Он поставляется с промежуточным программным обеспечением Express, а также может использоваться отдельно.
Если все, для чего Вы нуждаетесь в хеше, является членством, рассмотрите использование Set
:
Набор
Набор реализации набор незаказанных значений без дубликатов. Это - гибрид интуитивных средств взаимодействия Массива и быстрого поиска Хеша.
Набор прост в использовании с [1 114] Счетный объекты (реализующий
each
). Большинство методов инициализатора и бинарных операторов принимают универсальный Счетный объекты помимо наборов и массивов. Счетный объект может быть преобразован в [1 117] Набор использованиеto_set
метод.Набор Хеш использования как устройство хранения данных, таким образом, необходимо отметить следующие моменты:
- Равенство элементов определяется согласно
Object#eql?
иObject#hash
.- Набор предполагает, что идентификационные данные каждого элемента не изменяются, в то время как это хранится. Изменение элемента набора представит набор к ненадежному состоянию.
- , Когда строка должна быть сохранена, замороженная копия строки хранится вместо этого, если исходная строка уже не замораживается.
Сравнение
операторы сравнения
<
,>
,<=
и>=
реализованы как стенография для {надлежащий _} {подмножество?, надмножество?} методы. Однако<=>
оператор намеренно не учтен, потому что не каждая пара наборов сопоставима. ({x, y} по сравнению с {x, z}, например)Пример
require 'set' s1 = Set.new [1, 2] # -> #<Set: {1, 2}> s2 = [1, 2].to_set # -> #<Set: {1, 2}> s1 == s2 # -> true s1.add("foo") # -> #<Set: {1, 2, "foo"}> s1.merge([2, 6]) # -> #<Set: {1, 2, "foo", 6}> s1.subset? s2 # -> false s2.subset? s1 # -> true
[...]
Общедоступные Методы класса
новый (перечисление = ноль)
Создает новый набор, содержащий элементы данного счетного объекта.
, Если блок дан, элементы перечисления предварительно обрабатываются данным блоком.
Вот аккуратный способ кэшировать поиски с Хешем:
a = (1..1000000).to_a
h = Hash.new{|hash,key| hash[key] = true if a.include? key}
В значительной степени то, что это делает, создают конструктора по умолчанию для новых значений хэш-функции, затем хранит "верный" в кэше, если это находится в массиве (ноль иначе). Это позволяет ленивую загрузку в кэш, на всякий случай Вы не используете каждый элемент.
Выполнение некоторого сравнительного тестирования на предложениях до сих пор дает это, chrismear и основанное на присвоении создание хеша Gaius немного быстрее, чем мой метод карты (и присваивающийся ноль немного быстрее, чем присвоение верного). mtyaka и предложение Набора rampion приблизительно на 35% медленнее для создания.
До поисков, hash.include?(x)
очень крошечная сумма быстрее, чем hash[x]
; оба дважды как быстрое как set.include?(x)
.
user system total real
chrismear 6.050000 0.850000 6.900000 ( 6.959355)
derobert 6.010000 1.060000 7.070000 ( 7.113237)
Gaius 6.210000 0.810000 7.020000 ( 7.049815)
mtyaka 8.750000 1.190000 9.940000 ( 9.967548)
rampion 8.700000 1.210000 9.910000 ( 9.962281)
user system total real
times 10.880000 0.000000 10.880000 ( 10.921315)
set 93.030000 17.490000 110.520000 (110.817044)
hash-i 45.820000 8.040000 53.860000 ( 53.981141)
hash-e 47.070000 8.280000 55.350000 ( 55.487760)
код Сравнительного тестирования:
#!/usr/bin/ruby -w
require 'benchmark'
require 'set'
array = (1..5_000_000).to_a
Benchmark.bmbm(10) do |bm|
bm.report('chrismear') { hash = {}; array.each{|x| hash[x] = nil} }
bm.report('derobert') { hash = Hash[array.map {|x| [x, nil]}] }
bm.report('Gaius') { hash = {}; array.each{|x| hash[x] = true} }
bm.report('mtyaka') { set = array.to_set }
bm.report('rampion') { set = Set.new(array) }
end
hash = Hash[array.map {|x| [x, true]}]
set = array.to_set
array = nil
GC.start
GC.disable
Benchmark.bmbm(10) do |bm|
bm.report('times') { 100_000_000.times { } }
bm.report('set') { 100_000_000.times { set.include?(500_000) } }
bm.report('hash-i') { 100_000_000.times { hash.include?(500_000) } }
bm.report('hash-e') { 100_000_000.times { hash[500_000] } }
end
GC.enable
Я думаю , точка chrismear при использовании присвоения по созданию является большой. Для создания всего этого немного большим количеством Ruby-esque, тем не менее, я мог бы предложить присвоить что-то другой , чем nil
к каждому элементу:
hash = {}
array.each { |x| hash[x] = 1 } # or true or something else "truthy"
...
if hash[376] # instead of if hash.has_key?(376)
...
end
проблема с присвоением nil
состоит в том, что необходимо использовать has_key?
вместо []
, так как []
дают Вам nil
(Ваше значение маркера), если эти Hash
не имеет указанного ключа. Вы могли обходить это при помощи различного значения по умолчанию, но почему проходят дополнительную работу?
# much less elegant than above:
hash = Hash.new(42)
array.each { |x| hash[x] = nil }
...
unless hash[376]
...
end
Возможно, я неправильно понимаю цель здесь; Если Вы хотели знать, был ли X в массиве, почему бы не array.include? ("X")?
Rampion побеждают меня к нему. Набор мог бы быть ответом.
можно сделать:
require 'set'
set = array.to_set
set.include?(x)
Я вполне уверен, что нет умного способа с одним выстрелом создать этот хеш. Мой наклон состоял бы в том, чтобы просто быть явным и указать, что я делаю:
hash = {}
array.each{|x| hash[x] = nil}
Это не выглядит особенно изящным, но это ясно, и делает задание.
FWIW, Ваше исходное предложение (под Ruby 1.8.6, по крайней мере), кажется, не работает. Я получаю "ArgumentError: нечетное число аргументов в пользу Хеша" ошибка. Хеш. [] ожидает литерал, даже-lengthed список значений:
Hash[a, 1, b, 2] # => {a => 1, b => 2}
, таким образом, я пытался изменить Ваш код на:
hash = Hash[*array.map {|x| [x, nil]}.flatten]
, но производительность страшно:
#!/usr/bin/ruby -w
require 'benchmark'
array = (1..100_000).to_a
Benchmark.bm(15) do |x|
x.report("assignment loop") {hash = {}; array.each{|e| hash[e] = nil}}
x.report("hash constructor") {hash = Hash[*array.map {|e| [e, nil]}.flatten]}
end
дает
user system total real
assignment loop 0.440000 0.200000 0.640000 ( 0.657287)
hash constructor 4.440000 0.250000 4.690000 ( 4.758663)
, Если я не пропускаю что-то здесь, простой цикл присвоения кажется самым ясным и самым эффективным способом создать этот хеш.
Если Вы хотите быстро спросить, "X в массиве?" необходимо использовать Array#include?
.
Редактирование (в ответ на дополнение в OP):
, Если Вы хотите быстрый взгляд времена, используйте Набор. При наличии Хеша, который указывает на весь nil
, с глупа. Преобразование является легким процессом также с Array#to_set
.
require 'benchmark'
require 'set'
array = (1..1_000_000).to_a
set = array.to_set
Benchmark.bm(15) do |x|
x.report("Array.include?") { 1000.times { array.include?(500_000) } }
x.report("Set.include?") { 1000.times { set.include?(500_000) } }
end
Результаты на моей машине:
user system total real
Array.include? 36.200000 0.140000 36.340000 ( 36.740605)
Set.include? 0.000000 0.000000 0.000000 ( 0.000515)
необходимо рассмотреть просто использование набора для начала вместо массива так, чтобы преобразование никогда не было необходимо.
Ваш способ создать хеш выглядит хорошим. У меня был навоз вокруг в irb, и это иначе
>> [1,2,3,4].inject(Hash.new) { |h,i| {i => nil}.merge(h) }
=> {1=>nil, 2=>nil, 3=>nil, 4=>nil}
Если Вы ищете эквивалент этого кода Perl:
grep {$_ eq $element} @array
Можно просто использовать простой код Ruby:
array.include?(element)
Если вас не беспокоит, что такое хэш-значения
irb(main):031:0> a=(1..1_000_000).to_a ; a.length
=> 1000000
irb(main):032:0> h=Hash[a.zip a] ; h.keys.length
=> 1000000
Занимает секунду или около того на моем рабочем столе.