Create an array with evenly-spaced values - ruby

What is an easy way to generate an array that has values with a fixed distance between them?
For example:
1, 4, 7, 10,... etc
I need to be able to set start, end, and step distance.

Try using Range.step:
> (1..19).step(3).to_a
=> [1, 4, 7, 10, 13, 16, 19]

In Ruby 1.9:
1.step(12).to_a #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
1.step(12,3).to_a #=> [1, 4, 7, 10]
Or you can splat instead of to_a:
a = *1.step(12,3) #=> [1, 4, 7, 10]

Related

How to duplicate value of array in ruby

I have two arrays of integers, e.g.
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [7, 8, 9]
I would like to repeatedly duplicate the value of 'b' to get a perfectly matching array lengths like this:
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [7, 8, 9, 7, 8, 9, 7, 8, 9, 7]
We can assume that a.length > b.length
Assuming you mean
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [7, 8, 9]
then you can do:
b.cycle.take(a.length) #=> [7, 8, 9, 7, 8, 9, 7, 8, 9, 7]
<script src="//repl.it/embed/JJ3x/2.js"></script>
See Array#cycle and Enumerable#take for more details.
I would have used Array#cycle had it been available, but since it was taken I thought I'd suggest some alternatives (the first being my fav).
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [7, 8, 9]
[*b*(a.size/b.size), *b[0, a.size % b.size]]
#=> [7, 8, 9, 7, 8, 9, 7, 8, 9, 7]
Array.new(a.size) { |i| b[i % b.size] }
#=> [7, 8, 9, 7, 8, 9, 7, 8, 9, 7]
b.values_at(*(0..a.size-1).map { |i| i % b.size })
#=> [7, 8, 9, 7, 8, 9, 7, 8, 9, 7]

Directly convert splat to set

I'm using the below code to generate a set from a range:
my_set = *(1..10).to_set
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
As you can see, instead of getting a set, I get an array.
The statement works if I split it into two lines:
my_set = *(1..10)
my_set = my_set.to_set
# => #<Set: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}>
How can I get it to work as expected in one line?
You already had a set. Splatting it (*) gave you the array. Just don't splat:
my_set = (1..10).to_set # => #<Set: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}>
Set.new works as well with ranges:
Set.new(1..10)
=> #<Set: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}>
Just for fun, if you want to use splat operator (*):
my_set = (_ = *(1..10)).to_set
=> #<Set: {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}>
Note, that you should use assignment if you want to splat range.

Infinite loop in blocks in ruby

Why does the following piece of code result in an infinite loop of 3's?
a = [1,2,3,4,5,6,7,8,9,10]
a.each {|value| puts a.insert(value,3)}
The problem is that insert changes the original array:
a = [1,2,3,4,5,6,7,8,9,10]
a.each do |value|
a.insert(value, 3)
p a
end
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # original, ^ marks current value
# ^
# [1, 3, 2, 3, 4, 5, 6, 7, 8, 9, 10] # inserted 3 at position 1
# ^
# [1, 3, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10] # inserted 3 at position 3
# ^
# [1, 3, 3, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10] # inserted 3 at position 2
# ^
# [1, 3, 3, 3, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10] # inserted 3 at position 2
# ^
# [1, 3, 3, 3, 3, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10] # inserted 3 at position 2
# ^
# [1, 3, 3, 3, 3, 3, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10] # inserted 3 at position 2
# ^
# ... # continues forever ...
What you probably want instead is something like this:
a = [1,2,3,4,5,6,7,8,9,10]
a.each_index {|index| p a.dup.insert(index, 3) }
# [3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# [1, 3, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# [1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10]
# [1, 2, 3, 3, 4, 5, 6, 7, 8, 9, 10]
# [1, 2, 3, 4, 3, 5, 6, 7, 8, 9, 10]
# [1, 2, 3, 4, 5, 3, 6, 7, 8, 9, 10]
# [1, 2, 3, 4, 5, 6, 3, 7, 8, 9, 10]
# [1, 2, 3, 4, 5, 6, 7, 3, 8, 9, 10]
# [1, 2, 3, 4, 5, 6, 7, 8, 3, 9, 10]
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 3, 10]
each_index iterates over the indices, not the values. This is likely the correct thing to do here, because insert takes an index as first argument.
dup duplicates the array on every iteration so a remains unchanged.

how reverse a matrix object in ruby 1.9?

I am a beginner with Ruby. So I searched how reverse a matrix
1, 2, 3, 4 8, 9, 10, 11
4, 5, 6, 7 => 4, 5, 6, 7
8, 9, 10, 11 1, 2, 3, 4
I have tried:
require 'matrix'
m = Matrix[ [1,2,3,4],[4,5,6,7], [8,9,10,11] ]
m_rev = Matrix.build(m.row_size, m.column_size){|row|
m.row_size.downto(0){|i|
row = m.row(i)
}
}
Try: Matrix[*m.to_a.reverse]:
m = Matrix[ [1,2,3,4], [5,6,7,8], [9,10,11,12] ]
#=> Matrix[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
r = Matrix[*m.to_a.reverse]
#=> Matrix[[9, 10, 11, 12], [5, 6, 7, 8], [1, 2, 3, 4]]
Do not miss the *.
You can do something like:
m_rev = Matrix.rows m.to_a.reverse
You were on the right track, except that Matrix.build iterates over both rows and columns:
m_rev = Matrix.build(m.row_size, m.column_size){|row, column|
m[-row-1, column]
}
Simpler and faster:
m_rev = Matrix.rows(m.to_a.reverse)
# or
m_rev = Matrix[*m.to_a.reverse]

recursive removal of elements in array

Given an array of n elements, remove any adjacent pair of elements which are equal. Repeat this operation until there are no more adjacent pairs to remove; that will be the final array.
For e.g 1 2 2 3 4 should return the array 1 3 4.
please note array need not to be sorted.
check this test case also: 1,2,2,3,4,4,3,5 o/p should be 1,5.
(2,2) and (4,4) gets removed, then (3,3) which became adjacent after the removal of (4,4)
Any time you remove a pair of elements, you also need to see if you generated another pair that you want to remove.
The algorithm should follow naturally from that observation.
In Python:
>>> l=[1,2,2,3,4,4,3,5]
>>> [x for x in l if not l.count(x) > 1]
[1, 5]
This removes all integers that occur more than once in the list. This is a correct result for your example but I think that you are really trying to state something different. I think you are saying:
list:=(an unsorted list of integers)
while adjacent_pairs(list) is True:
remove_adjacent_pairs(list)
Once again, in Python:
#!/usr/bin/env python
def dedupe_adjacent(l):
for i in xrange(len(l) - 1, 0, -1):
if l[i] == l[i-1]:
del l[i-1:i+1]
return True
return False
def process_list(l):
print "input list: ",l
i=1
while(dedupe_adjacent(l)):
print " loop ",i,":",l
i+=1
print "processed list=",l
print
process_list([1,2,2,3,4,4,3,5])
process_list([1,2,2,3,4,4,6,3,5])
Output:
input list: [1, 2, 2, 3, 4, 4, 3, 5]
loop 1 : [1, 2, 2, 3, 3, 5]
loop 2 : [1, 2, 2, 5]
loop 3 : [1, 5]
processed list= [1, 5]
input list: [1, 2, 2, 3, 4, 4, 6, 3, 5]
loop 1 : [1, 2, 2, 3, 6, 3, 5]
loop 2 : [1, 3, 6, 3, 5]
processed list= [1, 3, 6, 3, 5]
The following:
function compress(arr) {
var prev, res = [];
for (var i in arr) {
if (i == 0 || (arr[i] != arr[i - 1]))
res.push(arr[i]);
}
return res;
}
compress([1, 2, 2, 3, 3, 3, 3, 4, 3, 3, 5, 6, 7, 8, 8]);
Returns:
[1, 2, 3, 4, 3, 5, 6, 7, 8]
Also (JavaScript 1.6 solution):
[1, 2, 2, 3, 3, 3, 3, 4, 3, 3, 5, 6, 7, 8, 8].filter(function(el, i, arr) {
return i == 0 || (el != arr[i - 1]);
})
Edit: Removing any item that appears in the array more than once requires a different solution:
function dedup(arr) {
var res = [], seen = {};
for (var i in arr)
seen[arr[i]] = seen[arr[i]] ? ++seen[arr[i]] : 1;
for (var j in arr) {
if (seen[arr[j]] == 1)
res.push(arr[j]);
}
return res;
}
The following:
dedup([1, 2, 2, 3, 4, 4, 3, 5]);
Produces:
[1, 5]
I have a solution to this in Java. You need to use replaceAll method in String class in Java. You can use regular expession to remove such adjacent redundant characters:
public class MyString {
public static void main(String[] args) {
String str = "12234435";
while(!str.replaceAll("(\\w)\\1+", "").equalsIgnoreCase(str))
str = str.replaceAll("(\\w)\\1+", "");
System.out.println(str);
}
}
You can find how to give a regular expression here
I would:
Sort the array.
From the start of the array, until you are at the last element of the array do:
`count` = count the number of array[i] elements.
remove the first `count` elements of the array if `count` > 1.
The following Python 3 code will remove duplicates from a list (array). It does this by scanning the array from start towards end and compares the target element with the element one larger. If they are the same they are removed. If the element pointer is not pointing at 0, then it is reduced by 1 in order to catch nested pairs. If the two compared elements are different then the pointer is incremented.
I'm sure there's a more pythonic way to remove two adjacent elements from a list, but I'm new to Python and haven't figured that out yet. Also, you'll want to get rid of the print(indx, SampleArray) statement--I left it in there to let you follow the progress in the output listing below.
# Algorithm to remove duplicates in a semi-sorted list
def CompressArray(SampleArray):
indx=0
while(indx < len(SampleArray)-1):
print(indx, SampleArray)
if(SampleArray[indx]==SampleArray[indx+1]):
del(SampleArray[indx])
del(SampleArray[indx])
if(indx>0):
indx-=1
else:
indx+=1
return SampleArray
Here are sample runs for:
[1, 2, 2, 3, 4]
[1, 2, 2, 3, 4, 4, 3, 5]
[1, 2, 2, 3, 3, 3, 3, 4, 3, 3, 5, 6, 7, 8, 8]
[1, 2, 2, 3, 4, 6, 7, 7, 6, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
[1, 1, 2, 3, 3, 2, 4, 5, 6, 6, 5, 7, 8, 8, 7, 4, 9]
================================
0 [1, 2, 2, 3, 4]
1 [1, 2, 2, 3, 4]
0 [1, 3, 4]
1 [1, 3, 4]
[1, 3, 4]
================================
0 [1, 2, 2, 3, 4, 4, 3, 5]
1 [1, 2, 2, 3, 4, 4, 3, 5]
0 [1, 3, 4, 4, 3, 5]
1 [1, 3, 4, 4, 3, 5]
2 [1, 3, 4, 4, 3, 5]
1 [1, 3, 3, 5]
0 [1, 5]
[1, 5]
================================
0 [1, 2, 2, 3, 3, 3, 3, 4, 3, 3, 5, 6, 7, 8, 8]
1 [1, 2, 2, 3, 3, 3, 3, 4, 3, 3, 5, 6, 7, 8, 8]
0 [1, 3, 3, 3, 3, 4, 3, 3, 5, 6, 7, 8, 8]
1 [1, 3, 3, 3, 3, 4, 3, 3, 5, 6, 7, 8, 8]
0 [1, 3, 3, 4, 3, 3, 5, 6, 7, 8, 8]
1 [1, 3, 3, 4, 3, 3, 5, 6, 7, 8, 8]
0 [1, 4, 3, 3, 5, 6, 7, 8, 8]
1 [1, 4, 3, 3, 5, 6, 7, 8, 8]
2 [1, 4, 3, 3, 5, 6, 7, 8, 8]
1 [1, 4, 5, 6, 7, 8, 8]
2 [1, 4, 5, 6, 7, 8, 8]
3 [1, 4, 5, 6, 7, 8, 8]
4 [1, 4, 5, 6, 7, 8, 8]
5 [1, 4, 5, 6, 7, 8, 8]
[1, 4, 5, 6, 7]
================================
0 [1, 2, 2, 3, 4, 6, 7, 7, 6, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
1 [1, 2, 2, 3, 4, 6, 7, 7, 6, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
0 [1, 3, 4, 6, 7, 7, 6, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
1 [1, 3, 4, 6, 7, 7, 6, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
2 [1, 3, 4, 6, 7, 7, 6, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
3 [1, 3, 4, 6, 7, 7, 6, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
4 [1, 3, 4, 6, 7, 7, 6, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
3 [1, 3, 4, 6, 6, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
2 [1, 3, 4, 4, 3, 8, 8, 5, 9, 10, 10, 9, 11]
1 [1, 3, 3, 8, 8, 5, 9, 10, 10, 9, 11]
0 [1, 8, 8, 5, 9, 10, 10, 9, 11]
1 [1, 8, 8, 5, 9, 10, 10, 9, 11]
0 [1, 5, 9, 10, 10, 9, 11]
1 [1, 5, 9, 10, 10, 9, 11]
2 [1, 5, 9, 10, 10, 9, 11]
3 [1, 5, 9, 10, 10, 9, 11]
2 [1, 5, 9, 9, 11]
1 [1, 5, 11]
[1, 5, 11]
================================
0 [1, 1, 2, 3, 3, 2, 4, 5, 6, 6, 5, 7, 8, 8, 7, 4, 9]
0 [2, 3, 3, 2, 4, 5, 6, 6, 5, 7, 8, 8, 7, 4, 9]
1 [2, 3, 3, 2, 4, 5, 6, 6, 5, 7, 8, 8, 7, 4, 9]
0 [2, 2, 4, 5, 6, 6, 5, 7, 8, 8, 7, 4, 9]
0 [4, 5, 6, 6, 5, 7, 8, 8, 7, 4, 9]
1 [4, 5, 6, 6, 5, 7, 8, 8, 7, 4, 9]
2 [4, 5, 6, 6, 5, 7, 8, 8, 7, 4, 9]
1 [4, 5, 5, 7, 8, 8, 7, 4, 9]
0 [4, 7, 8, 8, 7, 4, 9]
1 [4, 7, 8, 8, 7, 4, 9]
2 [4, 7, 8, 8, 7, 4, 9]
1 [4, 7, 7, 4, 9]
0 [4, 4, 9]
[9]
================================
I love Java, but functional solutions should get more time on this site.
In Haskell, doing things the way the question asks:
compress lst = if (length lst == length b) then lst else (compress b) where
b = helper lst
helper [] = []
helper [x] = [x]
helper (x:y:xs) = if (x == y) then (helper xs) else (x:helper (y:xs))
You can solve this problem in O(n) time, although it is a bit more complicated
compress' lst = reverse (helper [] lst) where
helper xs [] = xs
helper [] (x:xs) = helper [x] xs
helper (a:as) (x:xs)
| a == x = helper as xs
| otherwise = helper (x:a:as) xs
I think we could use a stack to check adjacent duplicated elements.
Scan the array. For each new element, if it is equal to the top element in the stack, drop it and pop the top element from the stack. Otherwise, push it into the stack.
Here is the stack based algorithm based upon the edited question.
// pseudo code, not tested
void RemoveDupp(vector<int> & vin, vector<int> & vout)
{
int i = 0, int j = -1;
vout.resize(vin.size());
while (i < vin.size())
{
if (j == -1 || vout[j] != vin[i])
vout[++j] = vin[i++]; //push
else
j--, i++; //pop
}
vout.resize(j + 1);
}

Resources