icmp 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +127 -0
- data/Rakefile +10 -0
- data/icmp.gemspec +27 -0
- data/lib/icmp.rb +83 -0
- data/lib/icmp/version.rb +3 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c63d2ee1af9ab07e259eeaa5b75892d277701f70
|
4
|
+
data.tar.gz: e0bbe8d2704c9d118a026bb739aecf9cf73a4595
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2226f3934d31d0352ea17a289d89a4dad36f0dc5bfac9ed84ac29385cc9086f3f132837b068e27e64e4213ab6239a792e0f8a04d8ddd0fe73dd3eccfc6dc4234
|
7
|
+
data.tar.gz: d34b9ef5e3b1eb9bc55232fdc98be1c0a172679b50d0844696183c350df03fe697448d98e27c38240ae314cea4d6dafbdc6eed02d26ce52f43391b0f479aad8f
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Artem Baikuzin
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# Interactive comparison of two sorted arrays
|
2
|
+
|
3
|
+
This gem provides module `Icmp` with only method `compare(current, previous)`. It yields events while comparing two arrays:
|
4
|
+
|
5
|
+
1. `:compare` - items present in both arrays
|
6
|
+
2. `:added` - item present only in current array
|
7
|
+
3. `:removed` - item present only in previous array
|
8
|
+
|
9
|
+
Arrays should be sorted by key. Method takes O(n) time to process.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'icmp'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install icmp
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'icmp'
|
31
|
+
|
32
|
+
# id - key element
|
33
|
+
current = [{ id: 1, state: :accept },
|
34
|
+
{ id: 2, state: :new },
|
35
|
+
{ id: 4, state: :canceled }]
|
36
|
+
|
37
|
+
previous = [{ id: 1, state: :new },
|
38
|
+
{ id: 3, state: :in_progress },
|
39
|
+
{ id: 4, state: :canceled }]
|
40
|
+
|
41
|
+
# Sets proc for key retrieve
|
42
|
+
Icmp.compare(current, previous, proc { |i| i[:id] }) do |event, cur_item, prev_item|
|
43
|
+
print "ID: #{cur_item[:id]}, "
|
44
|
+
|
45
|
+
case event
|
46
|
+
when :compare
|
47
|
+
if cur_item[:state] != prev_item[:state]
|
48
|
+
puts "new state = #{cur_item[:state]}, old state = #{prev_item[:state]}"
|
49
|
+
else
|
50
|
+
puts "item is not changed, state = #{cur_item[:state]}"
|
51
|
+
end
|
52
|
+
when :added
|
53
|
+
puts "item added with state = #{cur_item[:state]}"
|
54
|
+
when :removed
|
55
|
+
puts "item removed with state = #{cur_item[:state]}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
#### Output
|
61
|
+
```
|
62
|
+
ID: 1, new state = accept, old state = new
|
63
|
+
ID: 2, item added with state = new
|
64
|
+
ID: 3, item removed with state = in_progress
|
65
|
+
ID: 4, item is not changed, state = canceled
|
66
|
+
```
|
67
|
+
|
68
|
+
## Benchmark
|
69
|
+
```ruby
|
70
|
+
require 'icmp'
|
71
|
+
require 'benchmark/ips'
|
72
|
+
|
73
|
+
current = (1..20_000).to_a
|
74
|
+
previous = current.dup
|
75
|
+
|
76
|
+
Benchmark.ips do |x|
|
77
|
+
x.report('icmp') do
|
78
|
+
Icmp.compare(current, previous) do |event, cur_item, prev_item|
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
x.report('binary search') do
|
83
|
+
current.each do |cur_item|
|
84
|
+
prev_item = previous.bsearch { |i| cur_item - i }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
x.report('nested loops') do
|
89
|
+
current.each do |cur_item|
|
90
|
+
previous.each do |i|
|
91
|
+
if cur_item == i
|
92
|
+
break
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
x.compare!
|
99
|
+
end
|
100
|
+
```
|
101
|
+
|
102
|
+
#### Output
|
103
|
+
```
|
104
|
+
Warming up --------------------------------------
|
105
|
+
icmp 12.000 i/100ms
|
106
|
+
binary search 7.000 i/100ms
|
107
|
+
nested loops 1.000 i/100ms
|
108
|
+
Calculating -------------------------------------
|
109
|
+
icmp 135.101 (± 5.9%) i/s - 684.000 in 5.079674s
|
110
|
+
binary search 74.424 (± 4.0%) i/s - 378.000 in 5.089745s
|
111
|
+
nested loops 0.111 (± 0.0%) i/s - 1.000 in 8.970797s
|
112
|
+
|
113
|
+
Comparison:
|
114
|
+
icmp: 135.1 i/s
|
115
|
+
binary search: 74.4 i/s - 1.82x slower
|
116
|
+
nested loops: 0.1 i/s - 1211.96x slower
|
117
|
+
```
|
118
|
+
|
119
|
+
## Contributing
|
120
|
+
|
121
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ybinzu/icmp.
|
122
|
+
|
123
|
+
|
124
|
+
## License
|
125
|
+
|
126
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
127
|
+
|
data/Rakefile
ADDED
data/icmp.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'icmp/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'icmp'
|
8
|
+
spec.version = Icmp::VERSION
|
9
|
+
spec.authors = ['Artem Baikuzin']
|
10
|
+
spec.email = ['artembaykuzin@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = %q{Interactive comparison of two sorted arrays}
|
13
|
+
spec.description = %q{Compare two arrays in interactive way, yields block with arguments: event, current_item, previous_item. Takes O(n) time.}
|
14
|
+
spec.homepage = 'https://github.com/ybinzu/icmp'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features|benchmark)/})
|
19
|
+
end
|
20
|
+
spec.bindir = 'exe'
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
spec.add_development_dependency 'bundler', '~> 1.13'
|
25
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
26
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
27
|
+
end
|
data/lib/icmp.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module Icmp
|
2
|
+
##
|
3
|
+
# Interactively compares two sorted enumerables by key. Yields a block with
|
4
|
+
# event (:compare, :added, :removed), current and previous enumerable items.
|
5
|
+
#
|
6
|
+
# ==== Parameters
|
7
|
+
# * <tt>current</tt> - Array with current values
|
8
|
+
# * <tt>previous</tt> - Array to compare with, previous values
|
9
|
+
# * <tt>key_proc</tt> - Proc for retrieve key value from item. Sets to item
|
10
|
+
# by default
|
11
|
+
#
|
12
|
+
# ==== Example
|
13
|
+
# require 'icmp'
|
14
|
+
#
|
15
|
+
# # id - key element
|
16
|
+
# current = [{ id: 1, state: :accept },
|
17
|
+
# { id: 2, state: :new },
|
18
|
+
# { id: 4, state: :canceled }]
|
19
|
+
#
|
20
|
+
# previous = [{ id: 1, state: :new },
|
21
|
+
# { id: 3, state: :in_progress },
|
22
|
+
# { id: 4, state: :canceled }]
|
23
|
+
#
|
24
|
+
# # Sets proc for key retrieve
|
25
|
+
# Icmp.compare(current, previous, proc { |i| i[:id] }) do |event, cur_item, prev_item|
|
26
|
+
# print "ID: #{cur_item[:id]}, "
|
27
|
+
#
|
28
|
+
# case event
|
29
|
+
# when :compare
|
30
|
+
# if cur_item[:state] != prev_item[:state]
|
31
|
+
# puts "new state = #{cur_item[:state]}, old state = #{prev_item[:state]}"
|
32
|
+
# else
|
33
|
+
# puts "item is not changed, state = #{cur_item[:state]}"
|
34
|
+
# end
|
35
|
+
# when :added
|
36
|
+
# puts "item added with state = #{cur_item[:state]}"
|
37
|
+
# when :removed
|
38
|
+
# puts "item removed with state = #{cur_item[:state]}"
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# ===== Output
|
43
|
+
#
|
44
|
+
# ID: 1, new state = accept, old state = new
|
45
|
+
# ID: 2, item added with state = new
|
46
|
+
# ID: 3, item removed with state = in_progress
|
47
|
+
# ID: 4, item is not changed, state = canceled
|
48
|
+
#
|
49
|
+
def self.compare(current, previous, key_proc = proc { |item| item })
|
50
|
+
raise RuntimeError.new('Block should be specified') unless block_given?
|
51
|
+
|
52
|
+
while current.size > 0 && previous.size > 0
|
53
|
+
cur_item = current.first
|
54
|
+
prev_item = previous.first
|
55
|
+
|
56
|
+
cur_key = key_proc.call(cur_item)
|
57
|
+
prev_key = key_proc.call(prev_item)
|
58
|
+
|
59
|
+
if cur_key == prev_key
|
60
|
+
yield :compare, cur_item, prev_item
|
61
|
+
|
62
|
+
current = current.drop(1)
|
63
|
+
previous = previous.drop(1)
|
64
|
+
elsif cur_key < prev_key
|
65
|
+
yield :added, cur_item
|
66
|
+
|
67
|
+
current = current.drop(1)
|
68
|
+
else
|
69
|
+
yield :removed, prev_item
|
70
|
+
|
71
|
+
previous = previous.drop(1)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
current.each do |item|
|
76
|
+
yield :added, item
|
77
|
+
end
|
78
|
+
|
79
|
+
previous.each do |item|
|
80
|
+
yield :removed, item
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/icmp/version.rb
ADDED
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: icmp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Artem Baikuzin
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
description: 'Compare two arrays in interactive way, yields block with arguments:
|
56
|
+
event, current_item, previous_item. Takes O(n) time.'
|
57
|
+
email:
|
58
|
+
- artembaykuzin@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- icmp.gemspec
|
69
|
+
- lib/icmp.rb
|
70
|
+
- lib/icmp/version.rb
|
71
|
+
homepage: https://github.com/ybinzu/icmp
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata: {}
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
requirements: []
|
90
|
+
rubyforge_project:
|
91
|
+
rubygems_version: 2.6.10
|
92
|
+
signing_key:
|
93
|
+
specification_version: 4
|
94
|
+
summary: Interactive comparison of two sorted arrays
|
95
|
+
test_files: []
|