min_max 0.1.5 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d739946dcb0939e2e05893222c927f4dea0eda65da5c0a00156402de3e49c29
4
- data.tar.gz: 61b4453a94b93bb2ccefd0787a751cef5d3ef380ac0ed591c73c3b0afddc394b
3
+ metadata.gz: 2b43d258b5b9ccddc81016bb4c69c186df448ab7c51ae712f136ceed6218a145
4
+ data.tar.gz: 8c22dd5c5ac6ced73a789dc6813f62bc51168e3e48e2e2ca1b689187be7af8ac
5
5
  SHA512:
6
- metadata.gz: 70dd4402ca82a60cffbc451ea134ca9fc34391f28311d23726d22055bfc01db9ba62002f0d54c76282888993613f2bf5618dcfa7a964da39c6995747401f3a3f
7
- data.tar.gz: 31ada4f8ed50624701e389c6a1d50b83b75a585ef703d2f18c6511498dc9373647fa1f88d959ccdcbf56336d38dc550e1ce96710644f65970f2341549f843d53
6
+ metadata.gz: b02f4bdcbe8d60e8e2dfba61218a7958e8d97dd54a8939a0befcd363c796e049f11b7f7f58e014c8f8ead40773ea4ad9695fc69a89022e0bec6ac738ae4968ac
7
+ data.tar.gz: b55fc832a26ce35e955e275ea812b64de15f541fea714a57e107f078d287e3436a76a041a6152863ea1b9680282c0864096cb7784f1aaed525cf5b253b989465
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # MinMax Heap
2
2
 
3
- The MinMax Heap gem provides a high-performance minmax heap implementation for Ruby, written in Rust.
3
+ The MinMax Heap gem provides a high-performance minmax heap implementation for Ruby, written in Rust.
4
4
  The gem wraps the excellent [min-max-heap-rs](https://github.com/tov/min-max-heap-rs) Rust library.
5
- It allows for the creation of a min-max-heap and supporting operations like pushing and popping multiple items, iterating over heap items, and converting heaps to arrays.
5
+ It allows for the creation of a min-max-heap and supporting operations like pushing and popping multiple items, iterating over heap items, and converting heaps to arrays.
6
6
 
7
7
  ## Features
8
8
 
@@ -13,9 +13,9 @@ It allows for the creation of a min-max-heap and supporting operations like push
13
13
  - Convert heap to array with `#to_a`, `#to_a_asc` and `#to_a_desc`.
14
14
 
15
15
  ## Prequisites
16
- - You must have a working Rust compiler installed on your system.
16
+ - You must have a working Rust compiler installed on your system.
17
17
  ```bash
18
- curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs |
18
+ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs |
19
19
  ```
20
20
 
21
21
  ## Installation
@@ -79,6 +79,21 @@ heap.to_a_desc # => [5, 3, 1]
79
79
  heap.to_a # => Heap order
80
80
  ```
81
81
 
82
+ ## Iterate in order
83
+ ```ruby
84
+ heap.each_asc #<Enumerator: ...>
85
+ heap.each_desc #<Enumerator: ...>
86
+ ```
87
+
88
+ ## Peek at min and max items
89
+ ```ruby
90
+ heap.peek_min # => 1
91
+ heap.first # => 1
92
+
93
+ heap.peek_max # => 1
94
+ heap.last # => 1
95
+ ```
96
+
82
97
  ## Size
83
98
  ```ruby
84
99
  heap.size # => 4
@@ -100,3 +115,13 @@ heap.count(item)
100
115
  heap.contains?(item)
101
116
  ```
102
117
 
118
+ ## Performance
119
+ You can run the `benchmarks/benchmarks.rb` file inside this repository for comparison to other popular heap libraries:
120
+ * [rb_heap](https://github.com/florian/rb_heap)
121
+ * [algorithms](https://github.com/kanwei/algorithms)
122
+ * [ruby-heap](https://github.com/general-CbIC/ruby-heap)
123
+ * [pqueue](https://github.com/rubyworks/pqueue)
124
+
125
+ min-max should be the fastest to pop from a large heap, often by a significant margin, while also offering both min and max operations from a single heap.
126
+ Some options are faster at pushing individual items, but the difference is within the same order of magnitude.
127
+ Batch pushing to min-max also significantly increases insert speed.
@@ -73,13 +73,13 @@ pqueue = PQueue.new()
73
73
  mm_hp = MinMax[]
74
74
 
75
75
  Benchmark.bm do |x|
76
- x.report("push_algos_heap"){ data.each{|d| pqueue.push(d) } }
76
+ x.report("push_pqueue_heap"){ data.each{|d| pqueue.push(d) } }
77
77
  x.report("push_mm_heap"){ data.each{|d| mm_hp.push(d) } }
78
78
  x.report("push_mm_heap_batches"){ mm_hp = MinMax[]; data.each_slice(1000){|d| mm_hp.push(*d) } }
79
79
  end
80
80
 
81
81
  Benchmark.bm do |x|
82
- x.report("pop_algos_heap"){ 100_000.times{|d| minheap.pop } }
82
+ x.report("pop_pqueue_heap"){ 100_000.times{|d| pqueue.pop } }
83
83
  x.report("pop_mm_heap"){ 100_000.times{|d| mm_hp.pop_min } }
84
84
  x.report("pop_mm_heap_batches"){ 1000.times{|d| mm_hp.pop_min(100) } }
85
85
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class MinMax
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.7"
5
5
  end
data/lib/min_max.rb CHANGED
@@ -6,7 +6,7 @@ require_relative "min_max/min_max"
6
6
  class MinMax
7
7
  class Error < StandardError; end
8
8
 
9
- attr_reader :priority_blk, :storage, :mtx
9
+ attr_reader :priority_blk, :storage
10
10
 
11
11
  def self.[](*args, &blk)
12
12
  new(*args, &blk)
@@ -16,8 +16,7 @@ class MinMax
16
16
  self._new.tap{|s|
17
17
  s.instance_eval{
18
18
  @priority_blk = (blk || proc{|x| x.respond_to?(:priority) ? x.priority : x.to_i })
19
- @storage = Hash.new{|h,k| h[k] = [0, nil] }
20
- @mtx ||= Mutex.new
19
+ @storage = Hash.new{|h,k| h[k] = [0, nil] }.compare_by_identity
21
20
  }
22
21
  s.push(*args)
23
22
  }
@@ -25,13 +24,13 @@ class MinMax
25
24
 
26
25
  def push(*args)
27
26
  mapped = args.map do |a|
28
- hash = a.hash
29
- entry = self.storage[hash]
27
+ object_id = a.object_id
28
+ entry = self.storage[object_id]
30
29
  entry[0] += 1
31
30
  entry[1] ||= a
32
31
  [
33
32
  (self.priority_blk.call(a) rescue 0),
34
- hash
33
+ object_id
35
34
  ]
36
35
  end
37
36
  _push(mapped)
@@ -51,19 +50,27 @@ class MinMax
51
50
  popped.kind_of?(Array) ? popped.map{|p| retrieve(p) } : retrieve(popped)
52
51
  end
53
52
 
54
- def peek_min(*args)
55
- peeked = _peek_min(*args)
56
- peeked.kind_of?(Array) ? peeked.map{|p| retrieve(p, false) } : retrieve(popped, false)
53
+ def peek_min
54
+ retrieve(_peek_min, false)
57
55
  end
58
56
 
59
- def peek_max(*args)
60
- peeked = _peek_max(*args)
61
- peeked.kind_of?(Array) ? peeked.map{|p| retrieve(p, false) } : retrieve(popped, false)
57
+ def peek_max
58
+ retrieve(_peek_max, false)
59
+ end
60
+
61
+ def first
62
+ peek_min
63
+ end
64
+
65
+ def last
66
+ peek_max
62
67
  end
63
68
 
64
69
  def each(*args, &blk)
65
70
  if block_given?
66
- mtx.synchronize { _each(*args).map{|p| blk[retrieve(p, false)] } }
71
+ _each(*args) do |p|
72
+ blk[retrieve(p, false)]
73
+ end
67
74
  else
68
75
  to_enum(:each, *args)
69
76
  end
@@ -74,31 +81,42 @@ class MinMax
74
81
  end
75
82
 
76
83
  def count(val)
77
- counts.has_key?(val.hash) ? counts[val.hash] : 0
84
+ storage.has_key?(val.object_id) ? storage[val.object_id].first : 0
78
85
  end
79
86
 
80
87
  def contains?(val)
81
- counts.has_key?(val.hash) && counts[val.hash] > 0
88
+ storage.has_key?(val.object_id)
82
89
  end
83
90
 
84
91
  def to_a_asc
85
- mtx.synchronize { _to_a_asc.map{|p| retrieve(p, false) } }
92
+ return to_enum(:to_a_asc) unless block_given?
93
+ _to_a_asc.map{|p| retrieve(p, false) }
86
94
  end
87
95
 
88
96
  def to_a_desc
89
- mtx.synchronize { _to_a_desc.map{|p| retrieve(p, false) } }
97
+ return to_enum(:to_a_desc) unless block_given?
98
+ _to_a_desc.map{|p| retrieve(p, false) }
99
+ end
100
+
101
+ def each_asc
102
+ return to_enum(:each_asc) unless block_given?
103
+ _to_a_asc.each{|p| yield retrieve(p, false) }
104
+ end
105
+
106
+ def each_desc
107
+ return to_enum(:each_desc) unless block_given?
108
+ _to_a_desc.map{|p| retrieve(p, false) }
90
109
  end
91
110
 
92
111
  def inspect
93
- "MinMax[#{_each.first(10).map{|v| retrieve(v, false).to_s }.join(", ")}#{size > 10 ? ", ..." : ""}]"
112
+ "MinMax[#{each.first(10).map(&:to_s).join(", ")}#{size > 10 ? ", ..." : ""}]"
94
113
  end
95
114
 
96
115
  private
97
- def retrieve(hash, remove=true)
98
- entry = self.storage[hash]
99
- self.storage.delete(hash) if remove && (entry[0] -= 1) == 0
116
+ def retrieve(object_id, remove=true)
117
+ entry = self.storage[object_id]
118
+ self.storage.delete(object_id) if remove && (entry[0] -= 1) == 0
100
119
  entry[1]
101
120
  end
102
121
 
103
122
  end
104
-
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: min_max
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter Coppieters
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-02-25 00:00:00.000000000 Z
10
+ date: 2025-01-03 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rb_sys
@@ -79,7 +78,6 @@ licenses:
79
78
  metadata:
80
79
  allowed_push_host: https://rubygems.org
81
80
  homepage_uri: https://github.com/wouterken/min_max
82
- post_install_message:
83
81
  rdoc_options: []
84
82
  require_paths:
85
83
  - lib
@@ -94,8 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
92
  - !ruby/object:Gem::Version
95
93
  version: 3.3.11
96
94
  requirements: []
97
- rubygems_version: 3.4.19
98
- signing_key:
95
+ rubygems_version: 3.6.2
99
96
  specification_version: 4
100
97
  summary: A min max heap extension for Ruby
101
98
  test_files: []