How to Merge Consecutive Repeating Elements in an Array

How do you merge consecutive repeating elements in an array?

def remove_consecutive_duplicates(xs)
[xs.first] + xs.each_cons(2).select do |x,y|
x != y
end.map(&:last)
end

remove_consecutive_duplicates([1, 2, 2, 3, 1])
#=> [1,2,3,1]

This returns a new array like uniq does and works in O(n) time.

Concatenate consecutive (related) objects in array using JavaScript

Use Array.reduce() to iterate the objects. If the last item in the accumulator has the same type as that of the current item (o), add the duration to the last item. If not add the current object to the accumulator.

const activities = [

{ type: 'car', duration: 60 },

{ type: 'car', duration: 140 },

{ type: 'ferry', duration: 60 },

{ type: 'car', duration: 100 }

];

const result = activities.reduce((r, o) => {

const last = r[r.length - 1];



if(last && last.type === o.type) last.duration += o.duration;

else r.push({ ...o });



return r;

}, []);

console.log(result);

How to reorder an Array to avoid consecutive duplicates

It was a very interesting one, here is my solution:


const original = [1,2,2,2,2,3,3,2,2,2,3,4]
console.log("Before: ", original)

let object_keys = {}

//Step 1: map all the values and how many times it duplicated
for(let val of original){
if(object_keys[val]){
object_keys[val]++
}else{
object_keys[val] = 1
}
}

console.log(object_keys) // { '1': 1, '2': 7, '3': 3, '4': 1 }

//Step 2: Run over the object and create a new array. the method is each iterate, append new key

const get_the_most_duplicated_val = (object_keys, except) => {
let max = 0
let key = ''
for(let v in object_keys){
if(object_keys[v] > max && !except.includes(v)){
max = object_keys[v]
key = v
}
}
return key
}

let merged = []
let rest = []

let merged_is_completed = false
while(!merged_is_completed){

const append_val = (key) => {
merged.push(key)
object_keys[key]--
if(object_keys[key] == 0){
delete object_keys[key]
}
}

const last_val = () => {
return merged[merged.length - 1]
}

let most_key = get_the_most_duplicated_val(object_keys, [])
append_val(most_key)
let most_key2 = get_the_most_duplicated_val(object_keys, [most_key])
append_val(most_key2)

if(Object.keys(object_keys).length == 1){
if(last_val() != Object.keys(object_keys)[0]){
append_val(Object.keys(object_keys)[0])
}
for(let i=0;i<object_keys[Object.keys(object_keys)[0]];i++){
rest.push(Object.keys(object_keys)[0])
}
merged_is_completed = true
}
}
console.log("Merged: ", merged)
console.log("Rest: ", rest)

I put it in Codepen so you can test it by yourself :)
https://codepen.io/gofmannir/pen/vYXEmPa?editors=0011

In Ruby, how can I merge consecutive tokens in an array subject to a condition?

Here are two ways to do that. I assume that, as in the examples, no element (string) of the array begins or ends with a space.

#1

def join_some(arr, join_ch='&')
arr.drop(1).each_with_object([arr.first]).with_index(1) do |(s,a),i|
if (s[0] == join_ch && (i < arr.size - 1 || s.size > 1)) ||
(a.last[-1] == join_ch && (i > 1 || a.last.size > 1))
a.last << " #{s}"
else
a << s
end
end
end

join_some ["a", "&", "b", "d"] #=> ["a & b", "d"]
join_some ["a", "& b", "c"] #=> ["a & b", "c"]
join_some ["&", "b", "c"] #=> ["&", "b", "c"]
join_some ["a", "b", "&"] #=> ["a", "b", "&"]
join_some ["a", "&", "b", "&", "c"] #=> ["a & b & c"]
join_some ["a", "& b &", "c"] #=> ["a & b & c"]
join_some ["&", "& b", "c"] #=> ["& & b", "c"]
join_some [" &", "b", "c"] #=> [" & b", "c"]
join_some ["&", "&", "&"] #=> ["& & &"]
join_some ["a", "+ b", "+ c"], "+" #=> ["a + b + c"]

I am not certain if the return values from the last several examples are what is wanted.

#2

The first step is to join(c) all the elements of the array to form a single string, where c is a character that is not present in any element of the array. (I elected to use 0.chr #=> x00.) We can then use a regular expression r to split(r) the string as desired.

def join_some(arr, join_ch='&')
split_ch = 0.chr
r = /(?<=\A.|[^#{join_ch}])#{split_ch}(?=[^#{join_ch}]|.\z)/
arr.join(split_ch).split(r).map { |s| s.tr(split_ch, ' ') }
end

This method gives the same results as the first method for the 10 examples given above. The regular expression is expressed below in free-spacing mode with explanatory comments. Here join_ch #=> "&" and split_ch #=> \x00.

r = /
(?<= # begin positive lookbehind
\A # match the beginning of the string
. # match any char
| # or
[^#{join_ch}] # match any char other than the join char
) # end positive lookbehind
#{split_ch} # match split char
(?= # begin a positive lookahead
[^#{join_ch}] # match any char other than the join char
| # or
. # match any char
\z # match end of the string
) # end positive lookahead
/x # free-spacing regex definition mode
#=> (?<= # begin positive lookbehind
# \A # match the beginning of the string
# . # match any char
# | # or
# [^&] # match any char other than the join char
# ) # end positive lookbehind
# \x00 # match split char
# (?= # begin a positive lookahead
# [^&] # match any char other than the join char
# | # or
# . # match any char
# \z # match end of the string
# ) # end positive lookahead
# /x # free-spacing regex definition mode

Arrangement of elements to avoid duplicate on consecutive positions

Try something like this (Java syntax):

int max = M[0];
int sum = M[0];
for ( i = 1 ; i < M.length ; i++ ) {
if ( M[i] > max ) {
max = M[i];
}
sum = sum + M[i];
}

if ( 2*max <= s+1 ) {
System.out.println("possible");
} else {
System.out.println("NOT possible");
}

Time complexity: O(|M|)


The idea is that if you want to place those numbers into an array, you'll start with the longest sequence, then you choose the first longest sequence in order to avoid repeating.

E.g.:
----------- arr: []
1, 1, 1, 1
2, 2
3
----------- arr: [1]
1, 1, 1
2, 2
3
----------- arr: [1, 2]
1, 1, 1
2
3
----------- arr: [1, 2, 1]
1, 1
2
3
----------- arr: [1, 2, 1, 2]
1, 1
3
----------- arr: [1, 2, 1, 2, 1]
1
3
----------- arr: [1, 2, 1, 2, 1, 3]
1
----------- arr: [1, 2, 1, 2, 1, 3, 1]

So, if the maximum number from M is at most the sum of the others + 1, it's possible to obtain that array without repeats:

max <= sum_of_the_others + 1      | + max

which is equivalent to

max + max <= sum_of_all_numbers + 1

which is equivalent to

2*max <= sum_of_all_numbers + 1

Count consecutive repeated elements in array in the same sequence as they are

You can iterate over the array, counting values while they are the same, and pushing a value to the result array when they are different:

$result = [];
$count = 0;
$current = $array[0];
for ($i = 0; $i < count($array); $i++) {
if ($array[$i] == $current) {
$count++;
}
else {
$result[] = array($current, $count);
$count = 1;
}
$current = $array[$i];
}
$result[] = array($current, $count);
print_r($result);

Output:

Array
(
[0] => Array
(
[0] => a
[1] => 1
)
[1] => Array
(
[0] => b
[1] => 1
)
[2] => Array
(
[0] => a
[1] => 3
)
[3] => Array
(
[0] => c
[1] => 2
)
[4] => Array
(
[0] => b
[1] => 2
)
[5] => Array
(
[0] => a
[1] => 4
)
)

Demo on 3v4l.org

Change consecutive duplicates into one value (Python)

a = [3,3,3,4,10,11,3,3,5,5,10]

new_a = []
for i in range(len(a)):
if a[i] != a[i-1]:
new_a.append(a[i])
print(new_a)

[3, 4, 10, 11, 3, 5, 10]

Eliminate consecutive duplicates of list elements

Nice opportunity to use Enumerable#chunk, as long as your list doesn't contain nil:

list.chunk(&:itself).map(&:first)

For Ruby older than 2.2.x, you can require "backports/2.2.0/kernel/itself" or use {|x| x} instead of (&:itself).

For Ruby older than 1.9.2, you can require "backports/1.9.2/enumerable/chunk" to get a pure Ruby version of it.



Related Topics



Leave a reply



Submit