How to sum the integer inside array of arrays? - arrays

a = [[5, 6], [6, 5], [7, 4], [1, 0, 0], [9, 9], [6, 8], [8, 6], [1, 8, 0], [9, 0]]
How can I sum the integers inside the inner array and return an array of sum of the inner array?
I need it to return [(5+6), (6+5), (7+4), (1+0+0), ...], thus [11, 11, 11, 1, 18, 14, 14, 9, 9]

a.map{|a| a.inject(:+)}
# => [11, 11, 11, 1, 18, 14, 14, 9, 9]

Try
sum_arry = a.map { |sub_arry| sub_arry.inject(&:+) }
Then sum_arry should be the array you want.

Use map + reduce
a.map { |a| a.reduce(:+) }

Related

Split array in groups of n, m, o groups or more

Is there any method to split an array like this?
[1, 2, 3, 4, 5, 6, 7, 8, 9].split(3, 4, 2)
#=> [[1, 2, 3],[4, 5, 6, 7],[8, 9]]
Immutable version with λ:
▶ splitter = ->(array, *parts) do
parts.reduce([[], 0]) do |acc, i|
right = acc.last + i
[acc.first << (acc.last...right), right]
end.first.map { |r| array[r] }
end
#⇒ #<Proc:0x0055ae3d9ae7c8#(pry):18 (lambda)>
▶ splitter.((1..9).to_a, 3, 4, 2)
#⇒ [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
No, there is none, but you can easily write one yourself.
class Array
def in_groups_of_n(*sizes)
sizes.map(&method(:shift))
end
end
Example:
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.in_groups_of_n(3, 4, 2)
# => [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
Demonstration
In case you want a none-destructive version, you can use a dup method:
class Array
def in_groups_of_n(*sizes)
duplicate = dup
sizes.map { |size| duplicate.shift(size) }
end
end
arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
arr.in_groups_of_n(3,4,2)
# => [[1, 2, 3], [4, 5, 6, 7], [8, 9]
arr
# => [1, 2, 3, 4, 5, 6, 7, 8, 9]
Demonstration
Here's a naive Array implementation:
class Array
def multi_split(*sizes)
r = []
e = self.each
sizes.each do |size|
t = []
size.times do
t << e.next
end
r << t
end
r
end
end
p [1, 2, 3, 4, 5, 6, 7, 8, 9].multi_split(3, 4, 2)
# [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
#Stefan mentioned it might make sense to implement it on Enumerable:
module Enumerable
def multi_split(*sizes)
Enumerator.new do |yielder|
e = self.each
sizes.each do |size|
yielder << Array.new(size){ e.next }
end
end
end
end
p [1, 2, 3, 4, 5, 6, 7, 8, 9].multi_split(3, 4, 2).to_a
# [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
Another option (lossless in event the splits are not equal to the array size
def split_at(arr,splits)
rest = arr.last(arr.size - splits.reduce(:+))
enum = arr.to_enum
splits.map do |n|
n.times.map { enum.next }
end.concat(rest.empty? ? [] : [rest])
end
Then called as
split_at (1..9), [3,4,2]
#=> [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
split_at (1..22), [3,4,2]
#=> [[1, 2, 3], [4, 5, 6, 7], [8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]]
Example
class Array
def split_by_number(*sizes)
sizes.each_with_object([]) { |n,a| a << [a.empty? ? 0 : a.last.sum, n] }.
map { |start, nbr| self[start, nbr] }
end
end
[1, 2, 3, 4, 5, 6, 7, 8, 9].split_by_number 3, 4, 2
#=> [[1, 2, 3], [4, 5, 6, 7], [8, 9]]
Note that
[3, 4, 2].each_with_object([]) { |n,a| a << [a.empty? ? 0 : a.last.sum, n] }
#=> [[0, 3], [3, 4], [7, 2]]

How to recursively find permutations of two dimensional array in Ruby

I have an array with elements that are arrays of varying sizes. For example:
[[3],[11,2],[11,2],[3]]
I would like to find permutations of all of the individual items in the nested arrays. For the array above, I'd like a return value of:
[
[3, 11, 11, 3],
[3, 11, 2, 3],
[3, 2, 11, 3],
[3, 2, 2, 3]
]
I have a solution that works, but it seems particularly long-winded:
array = [[3],[11,2],[11,2],[3]]
array.product(*array).map { |e| e.drop(1) }.uniq
How should I implement a recursive approach to this, and how would that work? I am having trouble wrapping my head around this.
The conventional way of solving this problem is to use the methods Array#product and Array#drop.
arr = [[3], [11,2], [11,2,7], [4]]
arr.first.product(*arr.drop(1))
#=> [[3, 11, 11, 4], [3, 11, 2, 4], [3, 11, 7, 4],
# [3, 2, 11, 4], [3, 2, 2, 4], [3, 2, 7, 4]]
If any element of arr contains duplicates the return value will also contain duplicates. If duplicates are not wanted, use
arr.map(&:uniq).first.product(*arr.drop(1))
The asker has, however, requested a recursive solution. That could be written as follows:
def prod(arr)
return arr if arr.size == 1
t = prod(arr.drop(1))
arr.first.flat_map { |x| t.map { |a| [x] + a } }
end
prod arr
#=> [[3, 11, 11, 4], [3, 11, 2, 4], [3, 11, 7, 4],
# [3, 2, 11, 4], [3, 2, 2, 4], [3, 2, 7, 4]]
Initialization:
#arr = [[3],[11,2],[11,2],[3]]
#perms = []
Function Definition:
def recursion(idx, temp = [])
if (idx == #arr.size) then #perms.push(temp.clone); return end
#arr[idx].each { |x| recursion(idx+1, temp << x); temp.pop }
end
Call :
recursion(0)
p #perms
=> [[3, 11, 11, 3], [3, 11, 2, 3], [3, 2, 11, 3], [3, 2, 2, 3]]

Ruby: match first, second, this etc elements from a dimensional array

I have an array of arrays. I want to concatenate the first, second, third elements of arrays.
Example arrays:
a = [[4, 5, 6], [1, 2, 3], [8, 9, 10]]
a1 = [[1, 2, 3], [8, 9, 10]]
a2 = [[4, 5, 6], [1, 2, 3], [8, 9, 10], [11, 21, 31]]
Output:
out of a: [[4,1,8],[5,2,9],[6,3,10]]
out of a1: [[1,8],[2,9],[3,10]]
out of a2: [[4,1,8,11],[5,2,9,21],[6,3,10,31]]
Use transpose method
a.transpose
=> [[4, 1, 8], [5, 2, 9], [6, 3, 10]]
Array#transpose:
[a, a1, a2].map(&:transpose)
# [
# [[4, 1, 8], [5, 2, 9], [6, 3, 10]],
# [[1, 8], [2, 9], [3, 10]],
# [[4, 1, 8, 11], [5, 2, 9, 21], [6, 3, 10, 31]]
# ]
Whenever Array#transpose can be used so can Enumerable#zip.
a.first.zip *a.drop(1)
#=> [[4,1,8],[5,2,9],[6,3,10]]

How to change value of an element in dictionary of arrays?

I have created a dictionary like this
var MyArray: [String:[String:[Int]]] = [
"xx": ["x1": [1, 2, 3], "x2": [4, 5, 6], "x3": [7, 8, 9]],
"yy": ["y1": [10, 11, 12], "y2": [13, 14, 15], "y3": [16, 17, 18]]]
How can I change the value 3 in "x1" in "xx" to an other number?
I don't know that this is the number 3 but i know that it is in MyArray["xx"]!["x1"]![2]
// example setup
var myArray: [String:[String:[Int]]] = [
"xx": ["x1": [1, 2, 3], "x2": [4, 5, 6], "x3": [7, 8, 9]],
"yy": ["y1": [10, 11, 12], "y2": [13, 14, 15], "y3": [16, 17, 18]]]
// value to be replaced
let oldNum = 3
// value to replace old value by
let newNum = 4
// extract the current value (array) for inner key 'x1' (if it exists),
// and proceed if 'oldNum' is an element of this array
if var innerArr = myArray["xx"]?["x1"], let idx = innerArr.index(of: oldNum) {
// replace the 'oldNum' element with your new value in the copy of
// the inner array
innerArr[idx] = newNum
// replace the inner array with the new mutated array
myArray["xx"]?["x1"] = innerArr
}
print(myArray)
/* ["yy": ["y3": [16, 17, 18], "y2": [13, 14, 15], "y1": [10, 11, 12]],
"xx": ["x1": [1, 2, 4], "x3": [7, 8, 9], "x2": [4, 5, 6]]]
^ ok! */
Based on the following Q&A:
Dictionary in Swift with Mutable Array as value is performing very slow? How to optimize or construct properly?
A more performant approach would be actually removing the inner array (for key "x1"); mutating it; and re-adding it to the dictionary
// check if 'oldNum' is a member of the inner array, and if it is: remove
// the array and mutate it's 'oldNum' member to a new value, prior to
// adding the array again to the dictionary
if let idx = myArray["xx"]?["x1"]?.index(of: oldNum),
var innerArr = myArray["xx"]?.removeValue(forKey: "x1") {
innerArr[idx] = newNum
myArray["xx"]?["x1"] = innerArr
}
print(myArray)
// ["yy": ["y3": [16, 17, 18], "y2": [13, 14, 15], "y1": [10, 11, 12]], "xx": ["x1": [1, 2, 4], "x3": [7, 8, 9], "x2": [4, 5, 6]]]
If you know the index of the number you would like to change out of the three, you can change the number 3 directly using the subscripts ["xx"]?["x1"]?[2].
var myArray = [
"xx": [
"x1": [1, 2, 3],
"x2": [4, 5, 6],
"x3": [7, 8, 9]
],
"yy": [
"y1": [10, 11, 12],
"y2": [13, 14, 15],
"y3": [16, 17, 18]
]
]
array["xx"]?["x1"]?[2] = 4

Removing subsets in array of Sets

Is there an efficient way to remove subsets from an array of sets
E.g. array of arrays
[[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
to output an array
[[2, 3, 4, 7, 8, 9, 10], [1, 5, 6]]
The key is guaranteeing the source sets are sorted in descending order of size. That way all supersets precede their subsets.
Here’s a generic function to do it. You could adapt it to take any kind of sequence of sequence of hashable and convert them to an array of sets on the way in:
func removeSubsets<T: Hashable>(source: [Set<T>]) -> [Set<T>] {
let sets = source.sorted { $0.count > $1.count }
var supersets: [Set<T>] = []
for set in sets {
if !contains(supersets, { set.isSubsetOf($0) }) {
supersets.append(set)
}
}
return supersets
}
removeSubsets([[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
It's still cubic unfortunately since contains is linear and so is isSubsetOf.
EDIT: here's the fully generic version:
func removeSubsets
<S0: SequenceType, S1: SequenceType
where S0.Generator.Element == S1,
S1.Generator.Element: Hashable>
(source: S0) -> [Set<S1.Generator.Element>]
{
let sets = map(source) { Set($0) }.sorted { $0.count > $1.count }
var supersets: [Set<S1.Generator.Element>] = []
for set in sets {
if !contains(supersets, { set.isSubsetOf($0) }) {
supersets.append(set)
}
}
return supersets
}
let a: [[Int]] = [
[2, 3, 4, 7, 8, 9, 10],
[1, 5, 6], [3, 7, 10],
[4, 8, 9], [5, 6],
[7, 10], [8, 9],
[6], [9]]
removeSubsets(a) // returns [{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
EDIT2: if you want the result to be an array of the original arrays (since converting them to sets loses their ordering), you could make the following change, which takes more space but is also slightly more efficient since it only converts the supersets to sets, not the subsets:
func removeSubsets<T: Hashable>(source: [[T]]) -> [[T]] {
// note, this is quite efficient since arrays are copy-on-write,
// so it is only really creating a new array of pointers
let sets = source.sorted { $0.count > $1.count }
var supersets: [Set<T>] = []
var result: [[T]] = []
for set in sets {
if !contains(supersets, { $0.isSupersetOf(set) }) {
supersets.append(Set(set))
result.append(set)
}
}
return result
}
removeSubsets([[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6]]
EDIT3: if you want to keep the original order of the sets (just with the subsets removed), you could tag them with a number on the way in before sorting, then re-sort them using it and strip it off the result at the end:
func removeSubsets<T: Hashable>(source: [[T]]) -> [[T]] {
let sets = sorted(enumerate(source)) { $0.1.count > $1.1.count }
var supersets: [Set<T>] = []
var result: [(Int,[T])] = []
for (n,set) in sets {
if !contains(supersets, { $0.isSupersetOf(set) }) {
supersets.append(Set(set))
result.append(n,set)
}
}
return result.sorted { $0.0 < $1.0 }.map { $1 }
}
// note, input not sorted in order of length
removeSubsets([[1, 5, 6], [2, 3, 4, 7, 8, 9, 10], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]])
// returns [[1, 5, 6], [2, 3, 4, 7, 8, 9, 10]]
Just like with any other (non-2D/set) array you could use an array extension like this ...
extension Array
{
func slice(indices:Int...) -> Array
{
var s = indices[0];
var e = self.count - 1;
if (indices.count > 1)
{
e = indices[1];
}
if (e < 0)
{
e += self.count;
}
if (s < 0)
{
s += self.count;
}
let count = (s < e ? e - s : s - e) + 1;
let inc = s < e ? 1 : -1;
var result = Array();
var idx = s;
for i in 0 ..< count
{
result.append(self[idx]);
idx += inc;
}
return result;
}
}
Usage:
let a = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]];
let b = a.slice(0, 1);
let c = a.slice(3);
If your array does not contain duplicated int values, you can convert to Set to use some feature from Swift:
(Take a look at Performing Set Operations)
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html
Here is my code to get another Array which does not contain subsets. This method is not optimized, it works however.
//let arrayOfArray = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
//use set instead
var setArray : [Set<Int>] = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
setArray.sort({$0.count > $1.count}) //sort to have ordered array (biggest set at first)
var result = [Set<Int>]() //you will get your result in this variable.
for _aSet in setArray {
var isSubSet = false
for _exitSet in result {
if _aSet.isSubsetOf(_exitSet) {
isSubSet = true
break;
}
}
if (!isSubSet) {
result.append(_aSet)
}
}
This is the most efficient way I could think of:
let nArrays = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
nArrays
.reduce([Set<Int>]()) {
accu, el in let setEl = Set(el)
return contains(accu) {setEl.isSubsetOf($0)} ? accu : accu + [setEl]
}
//[{10, 2, 9, 4, 7, 3, 8}, {5, 6, 1}]
Instead of checking if every array is a subset of every other array, you just check if they're a subset of the already checked arrays. Of course, that returns an array of Sets, not an array of Arrays, but you can map() over it to convert it back:
let nArrays = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
nArrays
.reduce([Set<Int>]()) {
accu, el in let setEl = Set(el)
return contains(accu) {setEl.isSubsetOf($0)} ? accu : accu + [setEl]
}
.map{Array($0)}
//[[10, 2, 9, 4, 7, 3, 8], [5, 6, 1]]
You could do this:
let arrayOfArray = [[2, 3, 4, 7, 8, 9, 10], [1, 5, 6], [3, 7, 10], [4, 8, 9], [5, 6], [7, 10], [8, 9], [6], [9]]
let output = arrayOfArray[0...1]

Resources