String to array of integer - arrays

I have a string '[1. 2. 3. 4. 5.]' and I would like to convert to get only the int such that i obtain an array of integer of [1, 2, 3, 4, 5]
How do I do that? I tried using map but unsuccessful.

Use strip for remove [], split for convert to list of values which are converted to int in list comprehension:
s = '[1. 2. 3. 4. 5.]'
print ([int(x.strip('.')) for x in s.strip('[]').split()])
[1, 2, 3, 4, 5]
Similar solution with replace for remove .:
s = '[1. 2. 3. 4. 5.]'
print ([int(x) for x in s.strip('[]').replace('.','').split()])
[1, 2, 3, 4, 5]
Or with convert to float first and then to int:
s = '[1. 2. 3. 4. 5.]'
print ([int(float(x)) for x in s.strip('[]').split()])
[1, 2, 3, 4, 5]
Solution with map:
s = '[1. 2. 3. 4. 5.]'
#add list for python 3
print (list(map(int, s.strip('[]').replace('.','').split())))
[1, 2, 3, 4, 5]

Related

Sorting an array according to an element inside this array

I need to order my array according to an element of it, the reference element can vary.
For example, I would like the 3 to become the first element of the array and the 1, 2 to be put at the end.
array = [1, 2, 3, 4, 5, 6]
new_array = [3, 4, 5, 6, 1, 2]
The element may vary. If I start from 5, the behavior must be the same: the elements that precede are placed at the end, so I will have :
new_array = [5, 6, 1, 2, 3, 4]
If I understand correctly you want to rotate the array.
array
# [1, 2, 3, 4, 5, 6]
array.rotate(2) # or array.rotate(array.index(3))
# [3, 4, 5, 6, 1, 2]
https://apidock.com/ruby/v2_5_5/Array/rotate
Definitely use #rotate for this in actual use, but as an alternative, you could do something like #shift and #push until the desired element is at the beginning of the array.
def rotate(arr, elem)
arr2 = arr.clone
arr2.push(arr2.shift) until arr2.first == elem
arr2
end
irb(main):026:0> arr = [1, 2, 3, 4, 5, 6]
=> [1, 2, 3, 4, 5, 6]
irb(main):027:0> rotate(arr, 3)
=> [3, 4, 5, 6, 1, 2]
irb(main):028:0> arr
=> [1, 2, 3, 4, 5, 6]
Clearly, if elem is not in arr, this will run forever. You could implement some kind of check to ensure this doesn't happen, but that's just one reason you shouldn't actually do this as anything other than a learning exercise.
One approach would be to find the index of elem in arr and shift/push that many times. The &. operator may be useful in that situation to deal with the possibility of not finding elem in arr.

Need help filtering an array?

I am trying to remove odd numbers from an array.
arr = [1, 2, 3, 4, 5, 6, 7, 8, 10]
def remove_odd_nums(arr)
for x in arr
if x % 2 == 0
arr.delete(x)
end
end
end
print remove_odd_nums(arr)
# [1, 3, 5, 7, 10]
I can't seem to make this program work. The method works on the numbers except for the last one. What am I doing wrong?
You want to delete odd numbers but your program is deleting even numbers (x % 2 == 0 checks if x is an even number)
METHOD 1:
arr = [1, 2, 3, 4, 5, 6, 7, 8, 10]
arr.delete_if &:odd?
print arr
delete_if iterates by incrementing the index for arr, and deletes an element immediately after evaluating the block &:odd? with respect to the element. In other words, it is going through each element in array, and deleting the element if &:odd? is true.
&:odd?: a lambda function passing in an object to the odd? method, which returns true if the object is an odd number. Further explanations can be found what is the functionality of "&: " operator in ruby?
Note that method 1 actually MODIFIES the original array. For a way to create a new array of non-odd numbers, there is...
METHOD 2:
non_odds = arr.select{|i| not i.odd?}
TL;DR: don't modify an array while iterating it.
Let's see what's happening by printing the current value of x and arr inside the loop:
def remove_odd_nums(arr)
for x in arr
p x: x, arr: arr # <- debug output
if x % 2 == 0
arr.delete(x)
end
end
end
remove_odd_nums([1, 2, 3, 4, 5, 6, 7, 8, 10])
Output:
{:x=>1, :arr=>[1, 2, 3, 4, 5, 6, 7, 8, 10]}
{:x=>2, :arr=>[1, 2, 3, 4, 5, 6, 7, 8, 10]}
{:x=>4, :arr=>[1, 3, 4, 5, 6, 7, 8, 10]}
{:x=>6, :arr=>[1, 3, 5, 6, 7, 8, 10]}
{:x=>8, :arr=>[1, 3, 5, 7, 8, 10]}
The first two x values are as expected: 1 and 2. But then it moves on to 4, skipping 3. It also skips 5, 7, and 10. But why?
It's because you are modifying the array while iterating it. Think of the for loop as someone pointing to an element at a specific position. Initially it looks like this:
1 2 3 4 5 6 7 8 10 <- array
^ <- element
for then moves on to the next element:
1 2 3 4 5 6 7 8 10
^
at this point x % 2 == 0 becomes true and 2 is deleted from the array:
1 3 4 5 6 7 8 10
^
for isn't aware of this change and simply moves on to the next element:
1 3 4 5 6 7 8 10
^
which is why we have unintentionally skipped 3. The same happens for 5 and 7.
When for finally reaches 8:
1 3 5 7 8 10
^
it is being deleted:
1 3 5 7 10
^
and for stops looping because it seems to have reached the array's end.
Hello Practical1 just to clarify why do you want to destroy objects and array?
In case you on want to filter array and only select even numbers , you can try a combination of Array#select and Integer#even? method helpers
arr = arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# select all even numbers in an array
arr.select(&:even?) # shorthand for arr.select {|number| number.even? }
will return even numbers
[0] 2,
[1] 4,
[2] 6,
[3] 8,
[4] 10
source:
Array#select https://apidock.com/ruby/Array/select
Integer#even? https://ruby-doc.org/core-1.8.7/Integer.html
Ruby has fabulous methods to modify arrays in place based on the logic in a block.
To arrive at an array with only odd numbers, you can either remove the elements that don't meet a test or keep the number that do meet a test. You can either return a new array or use one of the in place modification methods.
To remove undesired values, use either .reject for a new array or .reject! to modify an existing array in place.
Since we are removing, we would use {|e| e%2!=0} inside the block for odd numbers:
> [1,2,3,4,5,6,7,8,9,10].reject {|e| e%2!=0}
=> [2, 4, 6, 8, 10] # new array
> arr = [1, 2, 3, 4, 5, 6, 7, 8, 10]
> arr.reject! {|e| e%2!=0}
=> [2, 4, 6, 8, 10] # arr modified in place
Rather than a block, you can also use the odd? logical test for the same result:
> [1,2,3,4,5,6,7,8,9,10].reject &:odd?
=> [2, 4, 6, 8, 10]
Or, you can keep the values desired and other values will not be kept. You would use {|e| e%2==0} inside the block for even values. Or you can use &:even? instead of the block.
You can use .keep_if to return a new array:
> arr
=> [1, 2, 3, 4, 5, 6, 7, 8, 10]
> [1,2,3,4,5,6,7,8,9,10].keep_if {|e| e%2==0}
=> [2, 4, 6, 8, 10] # new array.
Or use .select! to modify in place:
> arr = [1, 2, 3, 4, 5, 6, 7, 8, 10]
=> [1, 2, 3, 4, 5, 6, 7, 8, 10]
> arr.select! {|e| e%2==0}
=> [2, 4, 6, 8, 10]
> arr
=> [2, 4, 6, 8, 10] # arr modified in place

Sum every 3 elements of an array in ruby

Is there any efficient and short way to sum every 3 elements of an array?
ar = [1, 2, 3, 4, 5, 6, 7, 8, 1]
sum_ar = [6, 15, 16]
first 3 elements 1+2+3=6
next 3 elements 4+5+6=15
next 3 elements 7+8+1=15
...
if there are only two elements left, sum them
I could do something like this:
y=0
s=ar.size/3
((0..s).step(3).to_a).each do |i|
sum_ar[y]=ar[i..i+2].inject(:+)
y=y+1
end
but then I will miss the elements in case of such an array, where the size is not an exactly multiply of a 3:
ar=[1, 2, 3, 4, 5, 6, 7, 8]
A short way with Enumerable#each_slice:
[1, 2, 3, 4].each_slice(3).map { |e| e.inject(:+) } # => [6, 4]

Why doesn't this Python 3 for loop change every variable to 4?

list = [1,2,3,4,5]
print(list)
for each in list:
list[each] = 4
print(list)
And I get the result:
[1, 4, 3, 4, 4]
Line 4 seems to be setting "each" to 4 somehow...but I have no idea how. It's SUPPOSED to change the value at the current iterator to 4., which it also does at list[4].
Edit:
Wait wait wait, okay, 'each' is literally coming from the value inside the list? That's the only logical way this any sense, now that I think about it.
This will work better.
list = [1,2,3,4,5]
for each in range(len(list)):
list[each] = 4
print(list)
The problem you are running into is that your loop goes over the numbers from 1 - 5, but the index of the list starts at zero.
Adding a zero element to your list, or decrementing the each value by one in the loop makes your code work. But this way of doing it is flawed as you are depending on the content of the list to be in order and represent the positions.
list = [0,1,2,3,4,5] # zero added here.
for each in list:
list[each] = 4
print(list)
Your loop is actually doing this.
Loop 1: -> [1, 2, 3, 4, 5]
^
position 1 = 4.
Output: -> [1, 4, 3, 4, 5]
Loop 2: -> [1, 4, 3, 4, 5]
^
position 4 = 4.
Output: -> [1, 4, 3, 4, 4]
Loop 3: -> [1, 4, 3, 4, 4]
^
position 3 = 4. (it is already 4)
Output: -> [1, 4, 3, 4, 4]
Loop 4: -> [1, 4, 3, 4, 4]
^
position 4 = 4. (it is already 4)
Output: -> [1, 4, 3, 4, 4]
Loop 5: -> [1, 4, 3, 4, 4]
^
position 4 = 4. (it is already 4)
Output: -> [1, 4, 3, 4, 4]
Better use enumerate(), so you can skip the range(len()):
some_list = [1,2,3,4,5]
for i, item in enumerate(some_list):
some_list[i] = 4
print(some_list)
[4, 4, 4, 4, 4]
This will change each item in some_list to 4 by its index.
Why your way doesn't work
The thinking error you probably make it that the first item in a list has index 0, not 1 :)
"doing it your way" would then be:
some_list = [1,2,3,4,5]
print(some_list)
for each in some_list:
some_list[each-1] = 4
print(some_list)
[1, 2, 3, 4, 5]
[4, 4, 4, 4, 4]
EDIT
Another way to show what #JensB is explaining is to run the code below. It is exactly showing what happens in each of the iterations:
some_list = [1,2,3,4,5]
print(some_list)
for each in some_list:
some_list[each] = 4
print("some_list["+str(each)+"] = 4")
print(some_list)
[1, 2, 3, 4, 5]
some_list[1] = 4
[1, 4, 3, 4, 5]
some_list[4] = 4
[1, 4, 3, 4, 4]
some_list[3] = 4
[1, 4, 3, 4, 4]
some_list[4] = 4
[1, 4, 3, 4, 4]
some_list[4] = 4
[1, 4, 3, 4, 4]
When iterating over a list, you get the actual items, not the indexes (since the indexes are useless more often than not).
Actually, if you only need to iterate over the indexes, you could do it like this:
for i in range(len(your_list))
But to actually replace all items in the list with a single one, you could simply create a new one:
your_list = [4] * len(your_list)
Or if you prefer modifying the existing list:
your_list[:] = [4] * len(your_list)
Also, you should not name any variable list. This shadows the builtin list() function which is quite useful e.g. if you want to turn an iterable in a list (with list being shadowed you'd have to use [x for x in iterable] instead of list(iterable)).

Given an unsorted array, Find the maximum subtraction between two elements in the array

I've got this question from an Interview in Microsoft: Given an unsorted array, Find the maximum subtraction between two elements in the array is a way that:
(Index1, Index2) = arr[Index2] - arr[Index1]. Index1<Index2.
Example:
given the array: [1, 5, 3, 2, 7, 9, 4, 3] -> Output: (1,9)=8.
given the array: [4, 9, 2, 3, 6, 3, 8, 1] -> Output: (2,8)=6.
The naive solution works in O(n^2) times: Scan the first index for subtraction with all other indexes and save the max value, Continue to the next index and so on.
Is there any way to optimize this?
Fairly simple when you write it down. Rephrasing the problem, you want to find the largest element to the right of each element. Now given the first example, this is:
[1, 5, 3, 2, 7, 9, 4, 3]
=>
[9, 9, 9, 9, 9, 4, 3]
Now, notice the maximums array is just the cumulative maximums from the right. Given this property it is easy to construct an O(n) time algorithm.
Implementation in python:
def find_max(xs):
ys = []
cur_max = float('-inf')
for x in reversed(xs):
cur_max = max(x, cur_max)
ys.append(cur_max)
ys = ys[::-1][1:]
return max(y - x for x, y in zip(xs, ys))
We can also construct the maximums array lazily, doing so gives us O(1) memory, which is the best possible:
def find_max(xs):
cur_max = float('-inf')
cum_max = xs[-1]
for i in range(len(xs) - 2, -1, -1):
cur_max = max(cur_max, cum_max - xs[i])
cum_max = max(cum_max, xs[i])
return cur_max
I think this is correct and O(nlogn): Split in the middle and select from right the max, from left the min value. Also split the the other 2 quarters, if one of them gives bigger result continue on that branch recursively.
Second example:
4, 9, 2, 3| 6, 3, 8, 1 -> 2 and 8
4, 9| 2, 3, 6, 3, 8, 1 -> 4 and 8
4, 9, 2, 3, 6, 3| 8, 1 -> 2 and 8
So working on the right split:
4, 9, 2, 3, 6, 3, 8| 1 -> 2 and 1
Selecting the 2 and 8 option. It also works for the first example.

Resources