Bad value returned by calculation - arrays

This function is ment to sum all of the numbers that are in an even index of the list, and then multiply this sum by the last number of the list.
checkio = [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41]
def checkzi(array):
if len(array) != 0:
sum_array = 0
for i in array:
x = array.index(i)
if (x % 2 == 0):
sum_array += int(i)
print (sum_array)
print (sum_array)
answer = (sum_array) * (array[len(array)-1])
return (answer)
else:
return 0
checkzi(checkio)
the 'print' output I get is:
-37
-56
-27
-24
-88
-52
-26
29
-36
-36
.
By this I can understand that the last number that was added correctly was 55. after 55, 84 wasn't added correctly.
More to that, the final sum that I get is -1476, while it is suppose to be 1968.
I can't find any reason for this. not something I can see anyway.
Any idea anyone?
Thanks!!

array.index() will always return the first index at which a value is found. So you're looping through every element, and then looking to see what index it's at--but if there are duplicate elements (which there are), then you only see the index of the first one, leading you to always add (or always exclude) that number whenever you encounter it.
A much cleaner (and quicker) way to do this is to only iterate over the even elements of the list in the first place, using Python's slice notation:
checkio = [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41]
def checkzi(array):
sum_array = 0
for value in array[::2]: #loop over all values at even indexes
sum_array += value
return sum_array * array[-1] # multiply by the last element in the original array
Using the built-in sum function, you could even one-line this whole thing:
def checkzi(array):
return sum(array[::2]) * array[-1]

The problem is that array.index() will return the first instance of a value. You have the value 84 twice - so since the first index is odd, you never add it.
You really need to keep track of the index, not rely on uniqueness of the values. You do this with
for idx, val in enumerate(array):
now your first value will be the index, and the second value will be the value. Test idx%2==0 and you can figure it out from here.
update here is the complete code, making clear (I hope) how this works:
checkio = [-37,-36,-19,-99,29,20,3,-7,-64,84,36,62,26,-76,55,-24,84,49,-65,41]
def checkzi(array):
if len(array) != 0:
sum_array = 0
for idx, x in enumerate(array):
print "testing element", idx, " which has value ", x
if (idx % 2 == 0):
sum_array += x
print "sum is now ", sum_array
else:
print "odd element - not summing"
print (sum_array)
answer = (sum_array) * (array[len(array)-1])
return (answer)
else:
return 0
checkzi(checkio)
Output:
testing element 0 which has value -37
sum is now -37
testing element 1 which has value -36
odd element - not summing
testing element 2 which has value -19
sum is now -56
testing element 3 which has value -99
odd element - not summing
testing element 4 which has value 29
sum is now -27
testing element 5 which has value 20
odd element - not summing
testing element 6 which has value 3
sum is now -24
testing element 7 which has value -7
odd element - not summing
testing element 8 which has value -64
sum is now -88
testing element 9 which has value 84
odd element - not summing
testing element 10 which has value 36
sum is now -52
testing element 11 which has value 62
odd element - not summing
testing element 12 which has value 26
sum is now -26
testing element 13 which has value -76
odd element - not summing
testing element 14 which has value 55
sum is now 29
testing element 15 which has value -24
odd element - not summing
testing element 16 which has value 84
sum is now 113
testing element 17 which has value 49
odd element - not summing
testing element 18 which has value -65
sum is now 48
testing element 19 which has value 41
odd element - not summing
48
You obviously want to take the print statements out - I added them to help explain the program flow.

Related

Hackerrank array manipulation assistance

This is related to the question "Manipulate Arrays" on hackerrank: https://www.hackerrank.com/challenges/crush/problem
Could you explain why this code subtracts from the 2nd element in the queries array and how is it totalling the numbers at the end. I added print statements to see why this works but I am stuck.
def arrayManipulation(n, queries):
arr = [0]*n
for i in queries:
arr[i[0] - 1] += i[2]
if i[1] != len(arr):
arr[i[1]] -= i[2]
maxval = 0
itt = 0
for q in arr:
itt += q
if itt > maxval:
maxval = itt
return maxval
Instead of adding the value to each element in the range, the value is added to the first element of the range and subtracted from the element after the last element of the range. This way, when iterating over the array from the beginning and summing all the values, you get the current value of each element. So, an example with n == 5:
0 0 0 0 0
query 1 3 100
100 0 0 -100 0
query 2 4 200
100 200 0 -100 -200
If you now iterate over the array and sum the values while doing so, you will get the values:
100 300 300 200 0
which is the correct state of the array after such queries.
Edit: For queries where the ending index is equal to the length of the array the value is not subtracted from anything because there are no elements after the last one, so there is no point in doing so.

How to replace all occurences of elements of a two dimensional array in do loops in fortran

I've got stdin like that (elements are always > 10)
75 33 44 51
51 87 33 77
77 51 91 45
17 29 30 40
I would like to substitute 1 for one of the elements in each row (randomly - according to a random 1 =< n =< 4) and 0 for the others in the row, but so as to change equal elements throughout, i.e., 51 in the 1st, 2nd, and 3rd rows, 33 in in the 1st and 2nd rows, and 77 in the 2nd and 3rd rows but so that I don't get two 1s in a row. Assuming that n=4 for the 1st and 2nd row, and n=3 for the 3rd and 4th one, I should end up with
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 0
which is different from just putting n's in, i.e., I don't want
0 0 0 1
0 0 0 1
0 0 1 0
0 0 1 0
What I actually want is to change all occurrences of equal elements according to the values of their elements throughout. E.g., replacement 51 -> 1 should change 51 in the 1st, 2nd, and 3rd row to 1 as soon as 51 in the 1st row is changed to 1, but not their names. Their names c(i,j) in the array should, however, respond with their new value when called. Then, random n's should be overruled by already existing 0's and 1's in each next row, but should stay when a row is not so affected via links to the previous rows as the 4th row.
I didn't put in any Fortran specifics because I want to avoid the discussion being led astray. Constructive suggestions would be greatly appreciated.
You need to read about the WHERE construct. If I understand your description, this toy program should work for you.
program foo
implicit none
integer c(3,4), i, n
real u
c = transpose(reshape([75,33,44,51,51,87,33,77,77,51,91,45],[4,3]))
call prn ! Print original matrix
do i = 1, 3
call random_number(u)
n = 1 + floor(4*u)
print '(A,I0)', 'n = ', n
where(c(i,:) /= c(i,n)) c(i,:) = 0
where(c == c(i,n)) c = 1
call prn ! Print altered matrix
end do
contains
subroutine prn
integer i
do i = 1, 3
write(*,'(4(I0,1X))') c(i,:)
end do
print *
end subroutine prn
end program foo

Finding minimum positive value and its position in each column of a matrix

I need to find the minimum positive values in each column and its position inside the column of a certain matrix. So if I have:
A = [1 4
2 3
3 6]
I need to obtain the values 1 and 3, and the positions 1 and 2. Doing this inside a for loop I obtain correctly the minimum values and its position, but it also catches the negative values:
for bit = 1:2
[y(bit),x(bit)] = min(A(:,bit));
end
And if I use:
[y(bit),x(bit)] = min(A(A(:,bit)>0));
I don't receive the expected result. What I'm doing wrong? Thanks.
This can be easily achieved using inf and min...
New method using inf and no looping
Take some random example:
% Generated using A = randi([-100, 100], 10, 3)
A = [ 31 41 -12
-93 -94 -24
70 -45 53
87 -91 59
36 -81 -63
52 65 -2
49 39 -11
-22 -37 29
31 90 42
-66 -94 51];
Set all negative values to positive infinity, which will ensure they are never the minimum value in the column.
A(A<=0) = inf;
% if you want to preserve A, use A2=A; A2(A<=0)=inf;
Now you can just use the min function as expected.
[mins, idx] = min(A);
% mins = 31, 39, 29: as expected
% idx = 1, 7, 8: the indices of the above values in each column as expected.
By default, min will get the column-wise minimum as you want.To specify this explicitly, use min(A,[],1), see the documentation for more details.
Note that you could achieve the same result by using NaN instead of inf.
Your method
In response to why you were getting an unexpected result, it's because you weren't selecting the column of A in your loop, the second attempt should be corrected to
[y(bit),x(bit)] = min(A(A(:,bit)>0, bit));
However, this will still give an unexpected result! The minimums will be correct, but their indices will be lower than expected. This is because the indices will only count the positive values in each column, so you will get the nth positive number rather than the nth number. The easiest "workaround" is to abandon this method and use the quicker one above which doesn't require looping.

How to identify breaks within an array of MATLAB?

I have an array in MATLAB containing elements such as
A=[12 13 14 15 30 31 32 33 58 59 60];
How can I identify breaks in values of data? For example, the above data exhibits breaks at elements 15 and 33. The elements are arranged in ascending order and have an increment of one. How can I identify the location of breaks of this pattern in an array? I have achieved this using a for and if statement (code below). Is there a better method to do so?
count=0;
for i=1:numel(A)-1
if(A(i+1)==A(i)+1)
continue;
else
count=count+1;
q(count)=i;
end
end
Good time to use diff and find those neighbouring differences that aren't equal to 1. However, this will return an array which is one less than the length of your input array because it finds pairwise differences up until the last element, so naturally there will be one less. As such, when you find the locations that aren't equal to 1, make sure you add 1 to the locations to account for this:
>> A=[12 13 14 15 30 31 32 33 58 59 60];
>> q = find(diff(A) ~= 1) + 1
q =
5 9
This tells us that locations 5 and 9 in your array is where the jump happens, and that's right for your example data.
However, if you want to find the locations before the jump happens, such as in your code, don't add 1 to the result:
>> q = find(diff(A) ~= 1)
q =
4 8

Outside-In 2D array algorithm

I was given a series of non-negative integers.
43 18 5 67 1 72 16 17 15 93 38 6 83 10 49 98 7 47 61 52 71 79 82 52 8
I need to store it in m * n array from the Outside-In. As follows:
m = 5
n = 5
Then, I need to calculate the sum of certain part of the 2D array. (I have done this part already).
My ideal approach to store the numbers:
1. Initialize starti,startj = 0.
2. Initialize endi = m , endj = n.
3. Store the remaining numbers in array[starti][j], where j starts from startj and ends at endj.
4. Store the remaining numbers in array[i][endj], where i starts from starti and ends at endi.
5. Store the remaining numbers in array[endi][j], where j starts from endj and ends at startj.
6. Store the remaining numbers in array[i][endj], where i starts from endi and ends at starti.
7. Decrement endi and endj by 1.
8. Increment starti and start j by 1.
9. Repeat the steps 3 - 8 until the last number is stored.
Question : Is there any better way to solve this problem ?
Additional: I have been trying come up (but failed) with a formula to find where the last element is stored before doing all these operation.
Here is one way.
First you can start out thinking recursively
Have a method which has a signature like `fill(m,n,starting_position, direction)
The recursive version will look something like
fill(m,n, starting_position, direction) {
// If m=0 or n=0 you have a base case.
// Start at starting position, and fill in the direction.
// Decrement m or n, depending on the direction
// Compute new starting position and direction
// Recursively call fill with the updated m,n, starting_pos, direction
}
Now notice that this method is tail-recursive, and so you can get rid of the recursion and replace it with a while loop, with the condition of the while loop derived from the base case.

Resources