lib/darthjee/core_ext/array.rb
# frozen_string_literal: true
module Darthjee
module CoreExt
# @api public
#
# Module containing new usefull methods to Ruby vanilla Array
module Array
autoload :HashBuilder, 'darthjee/core_ext/array/hash_builder'
# Returns a Hash where the values are the elements of the array
#
# @param [::Array<::Object>] keys The keys of the hash
#
# @return [::Hash] hash built pairing the keys and values
#
# @example Creation of hash with symbol keys
# array = %w[each word one key]
# array.as_hash(%i[a b c d])
# # returns
# # { a: 'each', b: 'word', c: 'one', d: 'key' }
def as_hash(keys)
Array::HashBuilder.new(self, keys).build
end
# Calculate the average of all values in the array
#
# @return [::Float] average of all numbers
#
# @example Average of array of integer values
# array = [1, 2, 3, 4]
# array.average # returns 2.5
#
# @example An empty array
# [].average # returns 0
def average
return 0 if empty?
sum * 1.0 / length
end
# Maps the array using the given methods on each element of the array
#
# @param [::String,::Symbol] methods List of methods to be called
# sequentially on each element of the array
#
# @yield [element] block to be called on each element performing
# a final mapping
# @yieldparam [::Object] element element that will receive
# the method calls in chain
#
# @return [::Array] Array with the result of all method calls in chain
#
# @example Mapping to string out of float size of strings
# words = %w(big_word tiny oh_my_god_such_a_big_word)
# words.chain_map(:size, :to_f, :to_s) # returns ["8.0", "4.0", "25.0"]
#
# @example Mapping with a block mapping at the end
# words = %w(big_word tiny oh_my_god_such_a_big_word)
#
# output = words.chain_map(:size) do |size|
# (size % 2).zero? ? 'even size' : 'odd size'
# end # returns ["even size", "even size", "odd size"]
def chain_map(*methods, &block)
result = methods.inject(self) do |array, method|
array.map(&method)
end
return result unless block_given?
result.map(&block)
end
# Maps array chain fetching the keys of the hashes inside
#
# @param [::String,::Symbol] keys list of keys to be
# fetched from hashes inside
#
# @return [::Array] Array resulting of chain fetch of keys
#
# @example Multi level hash mapping
# array = [
# { a: { b: 1 }, b: 2 },
# { a: { b: 3 }, b: 4 }
# ]
# array,mapk(:a) # returns [{ b: 1 }, { b: 3 }]
# array.mapk(:a, :b) # returns [1, 3]
#
# @example Key missing
# array = [
# { a: { b: 1 }, b: 2 },
# { a: { b: 3 }, b: 4 }
# ]
# array.mapk(:c) # returns [nil, nil]
# array.mapk(:c, :d) # returns [nil, nil]
def mapk(*keys)
keys.inject(self) do |enum, key|
enum.map do |hash|
hash&.[] key
end
end
end
# Joins elements in a string using a proc
#
# Uses the proc given elements to Strig and a
# block for determinating the joining string
#
# @param [Proc] mapper Proc that will be used to map values
# to string before joining
#
# @return [String]
#
# @yield [previous, nexte]
# defines the string to be used to join the previous and
# next element
# @yieldparam [::Object] previous previous element that was joined
# @yieldparam [::Object] nexte next element that will be joined
#
# @example Addition of positive and negative numbers
# [1, 2, -3, -4, 5].procedural_join do |_previous, nexte|
# nexte.positive? ? '+' : ''
# end # returns '1+2-3-4+5'
#
# @example Spaced addition of positive and negative numbers
# mapper = proc { |value| value.to_f.to_s }
# array.procedural_join(mapper) do |_previous, nexte|
# nexte.positive? ? ' +' : ' '
# end # returns '1.0 +2.0 -3.0 -4.0 +5.0'
def procedural_join(mapper = proc(&:to_s))
return '' if empty?
map = map_to_hash(&mapper)
map.inject do |(previous, string), (nexte, nexte_string)|
link = yield(previous, nexte) if block_given?
[nexte, "#{string}#{link}#{nexte_string}"]
end.last.to_s
end
# Reeturns a random element of the array without altering it
#
# @return [Object] random element of the array
#
# @example Picking a random element of numeric array
# array = [10, 20, 30]
# array.random # might return 10, 20 or 30
# array # returns unchanged [10, 20, 30]
def random
self[Random.rand(size)]
end
# Reeturns a random element of the array removing it from the array
#
# @return [Object] random element of the array
#
# @example Slicing a random element of a numeric array
# array = [10, 20, 30]
# array.random! # might return 10, 20 or 30 ... lets say 20
# array # returns changed [20, 30]
def random!
slice!(Random.rand(size))
end
end
end
end
# Ruby Array received
#
# - mapk
# - procedural_join
# - chain_map
# - as_hash
# - random
# - random!
#
# @see Darthjee::CoreExt::Array
class Array
include Darthjee::CoreExt::Array
end