type_balancer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rubocop.yml +96 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/Dockerfile +38 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +101 -0
- data/LICENSE.txt +21 -0
- data/README.md +86 -0
- data/Rakefile +101 -0
- data/benchmark/README.md +90 -0
- data/benchmark/end_to_end_benchmark.rb +65 -0
- data/benchmark/quick_benchmark.rb +70 -0
- data/benchmark_output.log +1581 -0
- data/benchmark_results/ruby3.2.8.txt +55 -0
- data/benchmark_results/ruby3.2.8_yjit.txt +55 -0
- data/benchmark_results/ruby3.3.7.txt +55 -0
- data/benchmark_results/ruby3.3.7_yjit.txt +55 -0
- data/benchmark_results/ruby3.4.2.txt +55 -0
- data/benchmark_results/ruby3.4.2_yjit.txt +55 -0
- data/docs/benchmarks/README.md +180 -0
- data/examples/quality.rb +178 -0
- data/lib/type_balancer/alternating_filler.rb +46 -0
- data/lib/type_balancer/balancer.rb +126 -0
- data/lib/type_balancer/calculator.rb +218 -0
- data/lib/type_balancer/distribution_calculator.rb +21 -0
- data/lib/type_balancer/distributor.rb +61 -0
- data/lib/type_balancer/ordered_collection_manager.rb +95 -0
- data/lib/type_balancer/sequential_filler.rb +32 -0
- data/lib/type_balancer/version.rb +5 -0
- data/lib/type_balancer.rb +44 -0
- data/sig/type_balancer.rbs +85 -0
- data/type_balancer.gemspec +33 -0
- metadata +77 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
module TypeBalancer
|
2
|
+
VERSION: String
|
3
|
+
# See the writing guide of rbs: https://github.com/ruby/rbs#guides
|
4
|
+
|
5
|
+
class Error < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class ConfigurationError < Error
|
9
|
+
end
|
10
|
+
|
11
|
+
class ValidationError < Error
|
12
|
+
end
|
13
|
+
|
14
|
+
# Main class responsible for balancing items in a collection based on their types
|
15
|
+
class Balancer
|
16
|
+
def initialize: (Array[untyped] collection, ?type_field: Symbol | String, ?types: Array[String]?) -> void
|
17
|
+
def call: -> Array[untyped]
|
18
|
+
|
19
|
+
private
|
20
|
+
def calculate_ratios: (Hash[String, Array[untyped]] items_by_type) -> Array[Float]
|
21
|
+
def get_type: (untyped item) -> String
|
22
|
+
def extract_types: -> Array[String]
|
23
|
+
end
|
24
|
+
|
25
|
+
module Ruby
|
26
|
+
class Calculator
|
27
|
+
def self.calculate_positions: (total_count: Integer, ratio: Float, ?available_items: Array[Integer]?) -> Array[Integer]
|
28
|
+
|
29
|
+
private
|
30
|
+
def self.validate_inputs: (Integer total_count, Float ratio) -> void
|
31
|
+
def self.validate_available_items: (Array[Integer]? available_items, Integer total_count) -> void
|
32
|
+
def self.calculate_positions_without_available: (Integer total_count, Integer target_count) -> Array[Integer]
|
33
|
+
def self.calculate_positions_with_available: (Integer total_count, Integer target_count, Array[Integer] available_items) -> Array[Integer]
|
34
|
+
end
|
35
|
+
|
36
|
+
class BatchCalculator
|
37
|
+
class PositionBatch
|
38
|
+
attr_reader total_count: Integer
|
39
|
+
attr_reader available_count: Integer
|
40
|
+
attr_reader ratio: Float
|
41
|
+
|
42
|
+
def initialize: (total_count: Integer, available_count: Integer, ratio: Float) -> void
|
43
|
+
def valid?: -> bool
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.calculate_positions_batch: (PositionBatch batch, ?Integer iterations) -> Array[Integer]
|
47
|
+
private
|
48
|
+
def self.calculate_target_count: (PositionBatch batch) -> Integer
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class OrderedCollectionManager
|
53
|
+
def initialize: (Integer size) -> void
|
54
|
+
def place_at_positions: (Array[untyped] items, Array[Integer] positions) -> void
|
55
|
+
def fill_gaps_alternating: (Array[untyped] primary_items, Array[untyped] secondary_items) -> void
|
56
|
+
def fill_remaining_gaps: (Array[Array[untyped]] items_arrays) -> void
|
57
|
+
def result: -> Array[untyped]
|
58
|
+
private
|
59
|
+
def find_empty_positions: -> Array[Integer]
|
60
|
+
end
|
61
|
+
|
62
|
+
class SequentialFiller
|
63
|
+
def initialize: (Array[untyped] collection, Array[Array[untyped]] items_arrays) -> void
|
64
|
+
def self.fill: (Array[untyped] collection, Array[Integer] positions, Array[Array[untyped]] items_arrays) -> void
|
65
|
+
def fill_gaps: (Array[Integer] positions) -> void
|
66
|
+
end
|
67
|
+
|
68
|
+
class AlternatingFiller
|
69
|
+
def initialize: (Array[untyped] collection, Array[untyped] primary_items, Array[untyped] secondary_items) -> void
|
70
|
+
def self.fill: (Array[untyped] collection, Array[Integer] positions, Array[untyped] primary_items, Array[untyped] secondary_items) -> void
|
71
|
+
def fill_gaps: (Array[Integer] positions) -> void
|
72
|
+
end
|
73
|
+
|
74
|
+
class DistributionCalculator
|
75
|
+
def initialize: (?Float target_ratio) -> void
|
76
|
+
def calculate_target_positions: (Integer total_count, Integer available_items_count, ?Float target_ratio) -> Array[Integer]
|
77
|
+
end
|
78
|
+
|
79
|
+
module Distributor
|
80
|
+
def self.calculate_target_positions: (Integer total_count, Integer available_count, Float ratio) -> Array[Integer]
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.balance: (Array[untyped] collection, ?type_field: Symbol | String, ?type_order: Array[String]?) -> Array[untyped]
|
84
|
+
def self.extract_types: (Array[untyped] collection, Symbol | String type_field) -> Array[String]
|
85
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/type_balancer/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'type_balancer'
|
7
|
+
spec.version = TypeBalancer::VERSION
|
8
|
+
spec.authors = ['Carl Smith']
|
9
|
+
spec.email = ['carl@llweb.biz']
|
10
|
+
|
11
|
+
spec.summary = 'Balances types in collections'
|
12
|
+
spec.description = 'Balances types in collections by ensuring each type appears a similar number of times'
|
13
|
+
spec.homepage = 'https://github.com/llwebconsulting/type_balancer'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
spec.required_ruby_version = '>= 3.2.0'
|
16
|
+
|
17
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
18
|
+
spec.metadata['source_code_uri'] = 'https://github.com/llwebconsulting/type_balancer'
|
19
|
+
spec.metadata['changelog_uri'] = 'https://github.com/llwebconsulting/type_balancer/blob/main/CHANGELOG.md'
|
20
|
+
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
22
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
23
|
+
spec.files = Dir.chdir(__dir__) do
|
24
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
25
|
+
(File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor ext/
|
26
|
+
c_tests/])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
spec.bindir = 'exe'
|
30
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ['lib']
|
32
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: type_balancer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Carl Smith
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-04-10 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
12
|
+
description: Balances types in collections by ensuring each type appears a similar
|
13
|
+
number of times
|
14
|
+
email:
|
15
|
+
- carl@llweb.biz
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- ".rubocop.yml"
|
21
|
+
- ".ruby-version"
|
22
|
+
- CHANGELOG.md
|
23
|
+
- Dockerfile
|
24
|
+
- Gemfile
|
25
|
+
- Gemfile.lock
|
26
|
+
- LICENSE.txt
|
27
|
+
- README.md
|
28
|
+
- Rakefile
|
29
|
+
- benchmark/README.md
|
30
|
+
- benchmark/end_to_end_benchmark.rb
|
31
|
+
- benchmark/quick_benchmark.rb
|
32
|
+
- benchmark_output.log
|
33
|
+
- benchmark_results/ruby3.2.8.txt
|
34
|
+
- benchmark_results/ruby3.2.8_yjit.txt
|
35
|
+
- benchmark_results/ruby3.3.7.txt
|
36
|
+
- benchmark_results/ruby3.3.7_yjit.txt
|
37
|
+
- benchmark_results/ruby3.4.2.txt
|
38
|
+
- benchmark_results/ruby3.4.2_yjit.txt
|
39
|
+
- docs/benchmarks/README.md
|
40
|
+
- examples/quality.rb
|
41
|
+
- lib/type_balancer.rb
|
42
|
+
- lib/type_balancer/alternating_filler.rb
|
43
|
+
- lib/type_balancer/balancer.rb
|
44
|
+
- lib/type_balancer/calculator.rb
|
45
|
+
- lib/type_balancer/distribution_calculator.rb
|
46
|
+
- lib/type_balancer/distributor.rb
|
47
|
+
- lib/type_balancer/ordered_collection_manager.rb
|
48
|
+
- lib/type_balancer/sequential_filler.rb
|
49
|
+
- lib/type_balancer/version.rb
|
50
|
+
- sig/type_balancer.rbs
|
51
|
+
- type_balancer.gemspec
|
52
|
+
homepage: https://github.com/llwebconsulting/type_balancer
|
53
|
+
licenses:
|
54
|
+
- MIT
|
55
|
+
metadata:
|
56
|
+
homepage_uri: https://github.com/llwebconsulting/type_balancer
|
57
|
+
source_code_uri: https://github.com/llwebconsulting/type_balancer
|
58
|
+
changelog_uri: https://github.com/llwebconsulting/type_balancer/blob/main/CHANGELOG.md
|
59
|
+
rubygems_mfa_required: 'true'
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 3.2.0
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubygems_version: 3.6.2
|
75
|
+
specification_version: 4
|
76
|
+
summary: Balances types in collections
|
77
|
+
test_files: []
|