how to shrink an array if two consecutive numbers in an array are equal then remove one and increment other - arrays

How to shrink an array if two consecutive numbers in an array are equal then remove one and increment other
Example 1:
int a[6]={2,2,3,4,4,4};
// Output: 6
Example 2:
int b[7]={1,2,2,2,4,2,4};
// Output: {1,3,2,4,2,4}

lst = [2,2,3,4,4,4]
def shrink(lst):
idx = 0
while len(lst) > idx+1:
a, b = lst.pop(idx), lst.pop(idx)
if a == b:
lst.insert(idx, a+1)
idx = 0
else:
lst.insert(idx, b)
lst.insert(idx, a)
idx += 1
shrink(lst)
print(lst)
Prints:
[6]
For [5, 5, 5, 1] prints [6, 5, 1]

This can be done in near-linear time like so:
a = [2, 2, 3, 4, 4, 4]
b = [1, 2, 2, 2, 4, 2, 4]
c = [5, 5, 5, 1]
def shrink_array(a):
res = []
for i in range(1, len(a)+1):
if i < len(a) and a[i] == a[i-1]: # if equal to previous
a[i] += 1 # increment and move on
else:
if len(res) > 0 and res[-1] == a[i-1]: # if equal to last in res
res[-1] += 1 # increment last in res
else:
res.append(a[i-1]) # add to res
while len(res) > 1 and res[-1] == res[-2]: # shrink possible duplicates
res[-2] += 1
del res[-1]
return(res)
for arr in [a, b, c]:
print(shrink_array(arr))
Output:
[6]
[1, 3, 2, 4, 2, 4]
[6, 5, 1]

Related

Inner String array swap

I try to swap inner string array value with none additional array, stack...etc.
Example:
s = [1,2,3,4,5,6,7,8]
output= [1,5,2,6,3,7,4,8]
My solution shows as below, but I think isn't the best solution. Can someone correct my code efficiency?
[python3]
class Solution:
def inner_number(self, s):
i=len(s)//2
index=1
while i < len(s):
for j in range(i,index,-1):
s[j-1],s[j]=s[j],s[j-1]
i+=1
index+=2
return s
s = [1,2,3,4,5,6,7,8,9]
h = len(s)//2
res= []
if len(s)%2==1:
res = [j for i in zip(s[:h],s[h:]) for j in i] + [s[-1]]
else:
res = [j for i in zip(s[:h],s[h:]) for j in i]
print(res)
# output [1, 5, 2, 6, 3, 7, 4, 8, 9]
def inner_swap(input):
req_length = int(len(input)/2) if len(input) % 2 == 0 else int(len(input)/2)+1
s1 = input[:req_length]
s2 = input[req_length:]
result = [None]*len(input)
result[::2] = s1
result[1::2] = s2
return result
assert inner_swap([1, 2, 3, 4]) == [1, 3, 2, 4]
assert inner_swap([1, 2, 3, 4, 5]) == [1, 4, 2, 5, 3]

Merge two ordered arrays into one ordered array

I am writing a method that takes two sorted arrays and I want it to return a merged array with all the values sorted. Given the two arrays below:
array_one = [3, 4, 8]
array_two = [1, 5, 7]
I want my merge_arrays method to return:
[1, 3, 4, 5, 7, 8]
My current algorithm is below:
def merge_arrays(array_one, array_two)
merged_array_size = array_one.length + array_two.length
merged_array = []
current_index_on_one = 0
current_index_on_two = 0
current_merged_index = 0
for i in (0..merged_array_size - 1)
if array_one[current_index_on_one] < array_two[current_index_on_two]
merged_array[current_merged_index] = array_one[current_index_on_one]
current_index_on_one += 1
current_merged_index += 1
else
merged_array[current_merged_index] = array_two[current_index_on_two]
current_index_on_two += 1
current_merged_index += 1
end
end
return merged_array
end
I am getting an error 'undefined method `<' for nil:NilClass'. I don't understand how the conditional is receiving this. I debugged the variables in the conditionals and they are giving true or false values. I'm not sure what is causing this error.
Maybe I am missing the point but you can do:
(array_one + array_two).sort
=> [1, 3, 4, 5, 7, 8]
I am getting an error 'undefined method `<' for nil:NilClass'. I don't understand how the conditional is receiving this.
You start by comparing index 0 to index 0:
[3, 4, 8] [1, 5, 7]
0-----------0 #=> 3 < 1
Then you increment the lower value's index by 1:
[3, 4, 8] [1, 5, 7]
0--------------1 #=> 3 < 5
And so on:
[3, 4, 8] [1, 5, 7]
1-----------1 #=> 4 < 5
[3, 4, 8] [1, 5, 7]
2--------1 #=> 8 < 5
[3, 4, 8] [1, 5, 7]
2-----------2 #=> 8 < 7
At that point you get:
[3, 4, 8] [1, 5, 7]
2--------------3 #=> 8 < nil
Index 3 is outside the array's bounds, so array_two[current_index_on_two] returns nil and:
if array_one[current_index_on_one] < array_two[current_index_on_two]
# ...
end
becomes
if 8 < nil
# ...
end
resulting in ArgumentError(comparison of Integer with nil failed). If nil is on the left hand side, you'd get NoMethodError (undefined method `<' for nil:NilClass).
Here's one way you can write merge using recursion. Note, as you specified, both inputs must already be sorted otherwise the output will be invalid. The inputs can vary in size.
def merge (xs, ys)
if xs.empty?
ys
elsif ys.empty?
xs
else
x, *_xs = xs
y, *_ys = ys
if x < y
[x] + (merge _xs, ys)
else
[y] + (merge xs, _ys)
end
end
end
merge [ 1, 3, 4, 6, 8, 9 ], [ 0, 2, 5, 7 ]
# => [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Assuming you have two sorted arrays. You need to create pipeline using recursion going to crunch through each array. checking at each iteration to see
which value at index 0 of either array is lower, removing that from the array and appending that value to the result array.
def merge_arrays(a, b)
# build a holder array that is the size of both input arrays O(n) space
result = []
# get lower head value
if a[0] < b[0]
result << a.shift
else
result << b.shift
end
# check to see if either array is empty
if a.length == 0
return result + b
elsif b.length == 0
return result + a
else
return result + merge_arrays(a, b)
end
end
> a = [3, 4, 6, 10, 11, 15]
> b = [1, 5, 8, 12, 14, 19]
> merge_arrays(a, b)
#=> [1, 3, 4, 5, 6, 8, 10, 11, 12, 14, 15, 19]
I made slight changes to your code in order to make it work. See the comments inside.
array_one = [2, 3, 4, 8, 10, 11, 12, 13, 15]
array_two = [1, 5, 6, 7, 9, 14]
def merge_arrays(array_one, array_two)
array_one, array_two = array_two, array_one if array_one.length > array_two.length # (1) swap arrays to make satement (3) work, need array_two always be the longest
merged_array_size = array_one.length + array_two.length
merged_array = []
current_index_on_one = 0
current_index_on_two = 0
current_merged_index = 0
for i in (0...merged_array_size-1) # (2) three points to avoid the error
if (!array_one[current_index_on_one].nil? && array_one[current_index_on_one] < array_two[current_index_on_two]) # (3) check also if array_one is nil
merged_array[current_merged_index] = array_one[current_index_on_one]
current_index_on_one += 1
current_merged_index += 1
else
merged_array[current_merged_index] = array_two[current_index_on_two]
current_index_on_two += 1
current_merged_index += 1
end
end
merged_array[current_merged_index] = array_one[current_index_on_one] || array_two[current_index_on_two] # (4) add the missing element at the end of the loop, looks what happen if you comment out this line
return merged_array
end
p merge_arrays(array_one, array_two)
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
The error was coming because the loop was making one step over. The solution is to stop before and insert the missing element at the end of the loop.
It works also with:
# for i in (1...merged_array_size)
# and
# for i in (1..merged_array_size-1)
# and
# (merged_array_size-1).times do
arr1 = [3, 4, 8, 9, 12]
arr2 = [1, 5, 7, 8, 13]
arr = [arr1, arr2]
idx = [0, 0]
(arr1.size + arr2.size).times.with_object([]) do |_,a|
imin = [0, 1].min_by { |i| arr[i][idx[i]] || Float::INFINITY }
a << arr[imin][idx[imin]]
idx[imin] += 1
end
#=> [1, 3, 4, 5, 7, 8, 8, 9, 12, 13]

Removing elements from an array

Problem:
I have two arrays A and B:
A = [0, 1, 2, 3]; %A will always be from 0 to N where N in this case is 3.
B = [0, 1, 3, 1, 9, 4, 6, 2, 5, 9, 10, 11, 3, 8, 1, 5, 9, 10];
weights_B = [3, 4, 5, 6];
I want to compare the first element of A to the first 3 elements of B and the second element of A to the next 4 elements of B. If the elements of A are equal I remove it from B. So in example:
if (A(1) == B(1:3))
remove A(1) from B
Similarly,
I want to compare A(2) to the next 4 elements of B i.e. to B(4:7):
if (A(2) == B(4:7))
remove A(2) from B
I want to compare A(3) to the next 5 elements of B i.e. to B(8:12)
if (A(3) == B(8:12))
remove A(3) from B
I want to compare A(4) to the next 6 elements of B i.e. to B(13:18)
if (A(4) == B(13:18))
remove A(4) from B
Note: The array weights_B determines the number of elements in B that should be respectively compared to A(1), A(2), .. , A(4)
So in the end B should have the following elements:
B = [1, 3, 9, 4, 6, 5, 9, 10, 11, 8, 1, 5, 9, 10];
Needed Solution:
Is there any way I can do this without having to hard-code the indices?
Here's a way without hard-coding:
Bw = mat2cell(B, 1, weights_B); % split into chunks
result = cell(size(Bw)); % initiallize result
for k = 1: numel(A)
result{k} = Bw{k}(Bw{k}~=A(k)); % fill each chunk of the result
end
result = [result{:}]; % concatenate into a row vector
For the sake of diversity, here's a way to do this using splitapply:
function out = q50982235
A = 0:3;
B = [0, 1, 3, 1, 9, 4, 6, 2, 5, 9, 10, 11, 3, 8, 1, 5, 9, 10];
weights_B = [3, 4, 5, 6];
a_ind = 0; % acts as a "global" variable for the inner function
G = repelem( 1:numel(weights_B), weights_B ); % this creates a vector of groups
out = cell2mat( splitapply(#movdif, B, G) );
function out = movdif(B)
a_ind = a_ind + 1;
out = {B(B ~= A(a_ind))};
end
end
The above works because the order of processed groups is predictable.
This solution requires R2015b.
Try this
A = [0, 1, 2, 3];
B = [0, 1, 3, 1, 9, 4, 6, 2, 5, 9, 10, 11, 3, 8, 1, 5, 9, 10];
weights_B = A + A(end);
border_0 = zeros(size(A));
border_1 = zeros(size(A));
border_0(1) = 1;
border_1(end) = length(B);
for i= 2:length(A)
border_0(i) = border_0(i-1) + weights_B(i-1);
border_1(i-1) = border_0(i)-1;
end
C = [];
for i= 1:length(border_0)
shift = 0;
if (i > 1)
shift = border_1(i-1);
end
C = [C B( find(B(border_0(i):border_1(i))~=A(i)) + shift )]
end
A = [0, 1];
B = [0, 1, 3, 1, 4, 5, 6];
% Split B into cells
C{1} = B(1:3) ; % this can be coded if more splits are required
C{2} = B(4:end) ;
% removing the lements
for i = 1:2
C{i}(C{i}==A(i))=[] ; % remove the elements in C{i} present in A(i)
end
cell2mat(C)
Since you want to compare the elements of A with first 3 and then 4 elements of B respectively, you would need to involve indexes.
You could simply use loop for it.
for(int i=0;i<B.length;i++){
if((A[0]==B[i])&&i<3){
B[i]=B[i+1];
}
else if((A[0]==B[i])&&i>3){}
B[i]=B[i+1];
}
Then adjust the updated size of array B.

Compare current element to the remaining in Array (Ruby)

I want to compare the current element inside an iteration to the rest of the elements in the array. I have no issues from the starting point. The issue comes when I am looking to compare the current element to the elements behind it inside the array.
array = [1, 2, 3, 2, 3, 4, 5]
array.each_with_index do |num, index|
break if array[index + 1] == nil
if num > array[index + 1]
puts "#{num} is greater than the #{array[index + 1]}!"
else
puts "#{num} is less than the #{array[index + 1]}!"
end
end
I am looking for something like:
"3 is greater than 1 and 2 but less than 4 and 5"
Any ideas?
I'm assuming you want all of the elements in the array compared, so you could do something like the following, by making use of Array#select:
array = [1, 2, 3, 2, 3, 4, 5]
filtered_array = array.uniq
array.each do |i|
greater_than = filtered_array.select { |comp| comp < i }
less_than = filtered_array.select { |comp| comp > i }
puts "#{i} is greater than #{greater_than} but less than #{less_than}"
end
You could play with formatting the output, but this would give:
1 is greater than [] but less than [2, 3, 4, 5]
2 is greater than [1] but less than [3, 4, 5]
3 is greater than [1, 2] but less than [4, 5]
2 is greater than [1] but less than [3, 4, 5]
3 is greater than [1, 2] but less than [4, 5]
4 is greater than [1, 2, 3] but less than [5]
5 is greater than [1, 2, 3, 4] but less than []
partition breaks divides up the elements into two separate groups.
array = [1,2,3,4,5]
array.each do |n|
less_than, greater_than = *(array - [n]).partition { |m| m <= n }
text = []
text << "is greater than #{less_than.join(', ')}" if less_than.count > 0
text << "is less than #{greater_than.join(', ')}" if greater_than.count > 0
puts "#{n} #{text.join(' and ')}"
end
arr = [1, 2, 3, 2, 3, 4, 5]
a = arr.uniq.sort
#=> [1, 2, 3, 4, 5]
h = a.each_with_index.to_h
#=> {1=>0, 2=>1, 3=>2, 4=>3, 5=>4}
arr.each { |i| puts "#{i} is greater than #{a[0,h[i]]} but less than #{a[h[i]+1..-1]}" }
prints
1 is greater than [] but less than [2, 3, 4, 5]
2 is greater than [1] but less than [3, 4, 5]
3 is greater than [1, 2] but less than [4, 5]
2 is greater than [1] but less than [3, 4, 5]
3 is greater than [1, 2] but less than [4, 5]
4 is greater than [1, 2, 3] but less than [5]
5 is greater than [1, 2, 3, 4] but less than []

Iterate through array forwards then backwards

[1,2,3,4,5]
=>1,2,3,4,5,4,3,2,1
=>1,2,3,2,3,4,5,4,3 #I need to be able to reverse the iteration at certain points
I first tried something like:
a = [1,2,3,4,5]
a.each {|i|
if i % 9 == 0
a.reverse!
}
but that just reverses the entire array and starts counting from the index it left off on. I need to to shift the direction of each, so to speak.
i, counter = 0, 1 # initialize index to 0, counter to 1
while(i < a.length && i >= 0) do
puts a[i]
i+= counter # increment counter
counter*= -1 if(condition) # Multiply counter with -1 to reverse it
end
Well, here's a moving "cursor" for your array:
module Cursor
def current_index
#current_index ||= 0
end
def step
#current_index = current_index + direction
handle_boundary
end
def step_back
#current_index = current_index + (direction * -1)
handle_boundary
end
def handle_boundary
if current_index == length || current_index == 0
turn_around
end
end
def direction
#direction ||= 1
end
def turn_around
#direction = direction * -1
end
def current
self[current_index]
end
end
And here's how you use it:
array = [1,2,3,4,5]
arary.extend Cursor
array.current # returns the item in current position
array.step # moves a step forward, turns around when it reaches either end of the array
array.step_back # moves a step backward without switching the direction
array.turn_around # switch the direction
Now you can travel around as you want :D
You can make use of Enumerator class to create custom enumerable that can providing custom iteration through the array. In below code, I am monkey-patching Array class for convenience (also due to resemblance of the method to Array#cycle), though solution can be done without monkey-patching as well.
class Array
def reversible_cycle
Enumerator.new do |y|
index = 0
direction = :forward
loop do
direction = :backward if index + 1 >= size
direction = :forward if index <= 0
y << self[index]
index += (direction == :forward ? +1 : -1)
end
end
end
end
p [1,2,3,4,5].reversible_cycle.take(9)
#=> [1, 2, 3, 4, 5, 4, 3, 2, 1]
p [1,2,3,4,5].reversible_cycle.take(13)
#=> [1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4, 5]
p [1,2,3,4,5].reversible_cycle.take(17)
#> [1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4, 5, 4, 3, 2, 1]
p [1,2,3,4,5].reversible_cycle.take(21)
#=> [1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4, 5]
For scenarios where you are changing direction without iterating the array fully in one direction, you will have to give some examples so that one can see how to modify the above code to accommodate that
You could use Ruby's under-appreciated flip-flop operator.
arr = [1,2,3,4,5]
sz = arr.size
(2*sz-1).times { |i| puts i==0..i==arr.size-1 ? arr[i] : arr[sz-i-2] }
1
2
3
4
5
4
3
2
1

Resources