Symmetric 1D array Python - python

So I have
A = [1,2,3,4]
I want to check if the array is symmetric. So the output would be False
Another example would be
arr = [1,2,3,3,2,1]
out = fun(arr)
out = True
I have been trying by like
def checksymm(a):
flag = 0
for i in range(0,len(a)/2):
if np.abs(a[i]) == np.abs(a[-i]):
return True
else:
return False
What can I be doing wrong?
Thanks.

Corresponding of a[i] should be a[-1-i], not a[-i].
Besides, why not just reverse the list and compare each elements:
def isSymmetric(arr):
return (arr == arr[::-1]).all()

Probably the most efficient way would be to restrict the comparison to each half of the array:
n = len(arr) // 2
result = np.all(arr[:n] == arr[-1:-n - 1:-1])
With absolute values:
result = (np.abs(arr[:n]) == np.abs(arr[-1:-n - 1:-1])).all()
Both formulations should work directly with either lists or arrays.

When you compare, pay attention to the index, 0 with -1, 1 with -2 etc (not 1 with -1), so it should be i and -i-1 . Also instead of returning True after finding one equality , you should return after all of them are equal ...
arr = [1,2,3,3,2,1]
def checksymm(a):
for i in range(0,len(a)//2):
if a[i] != a[-i-1]: # or np.abs(a[i]) != np.abs(a[-i-1]) as in the original code
return False
return True
out = checksymm(arr)
print(out)
>>> True
And :
arr = [1,2,3,3,5,1]
out = checksymm(arr)
print(out)
>>> False
Edit : I tried to find the problem with your code and fix it, but I would recommand the answer of #songziming it's better.

Related

How to solve the duplicate integer issue in an array for the isValidSubsequence(array, sequence) question

prompt for isValidSubsequence
def isValidSubsequence(array, sequence):
index = -1
# issue is with initialising the index variable
if len(sequence)<=len(array):
for i in range(len(sequence)):
# i refers to the i in the sequence
if sequence[i] in array:
# causing a problem for repetitions such as array = [1,1,1,1,1] and subsequence = [1,1,1]
# array.index(sequence[i]) would call the first 1 instead of the second 1
if array.index(sequence[i]) > index:
index = array.index(sequence[i])
else:
return False
else:
return False
return True
else:
return False
How to solve this repeating 1s issue using my code?
The reason array.index(sequence[i]) calls the first 1 is because sequence[i] is 1 in your case, and that is the same as if you called array.index(1). The index function searches your array for 1 and as soon as it finds it, it returns its index, so it always finds the first 1 first and then stops looking and returns its index.
Try something like this, this should work:
def isValidSubsequence(array, sequence):
lastIndex = -1
if not len(array) >= len(sequence):
return False
for i in range(len(sequence)):
containsInt = False
for j in range(lastIndex + 1, len(array)):
if array[j] == sequence[i]:
containsInt = True
lastIndex = j
break
if not containsInt:
return False
return True
You are using lists, not arrays. list.index(x[, start[, end]]) can take positionals from where to where search - you could rewrite your algo to remember the last found position for each value and look for new values from that position.
BUT: this is irrelevant, you only need to concern yourself with how many of each element are in original and sequence and if one has at most equal of them...
The correct way to solve this ist to count the occurences of elements in the original, subtract the amount of occurences in the `sequence`` and evaluate your numbers:
If sequence is empty, contains elements not in original or contains more elements then inside original it can not be a subsequence:
from collections import Counter
def isValidSubsequence(array, sequence):
# check empty sequence
if not sequence:
return False
original = Counter(array)
# check any in seq that is not in original
if any(i not in original for i in sequence):
return False
# remove number of occurences in sequence from originals
original.subtract(sequence)
# check if too many of them in sequence
if any(v < 0 for v in original.values()):
return False
return True
Testcode:
source = [1,2,3,4]
test_cases = [[1], [2,4], [1,2,4] ]
neg_test_case = [[2,5], [9], []]
for tc in test_cases:
print(isValidSubsequence(source,tc), "should be True")
for ntc in neg_test_case:
print(isValidSubsequence(source,ntc), "should be False")
Output:
True should be True
True should be True
True should be True
False should be False
False should be False
False should be False
If you are not allowed to import, count yourself (expand this yourself):
# not efficient
counted = {d:original.count(d) for d in frozenset(original)}
# remove numbers
for d in sequence:
counted.setdefault(d,0)
counted[d] -= 1
This would be another way to answer the question.
def isValidSubsequence(array,sequence):
if len(array) >= len(sequence):
iter_sequence = iter(sequence)
last = next(iter_sequence)
total = 0
for i in array:
if i + total == last:
total += i
try:
last += next(iter_sequence)
except StopIteration:
return True
break
return False

Python Logic to find the sum of a sub list satisfying a condition

I need to find the sum of the list elements between -1 and -1.
I tried this solution,but it adds the elements 1,2,3 to 1,1,1,1 .Can you help me with a better logic ?
lis = [1,2,3,4,-1,1,1,1,1,-1,1,2,3]
sum = 0
newlis = []
for i in range(0,len(lis)-1):
if lis[i] == -1:
while i+1 < len(lis) and lis[i+1]!=-1:
sum = sum+lis[i+1]
i = i+1
print(sum)
You can use:
idx = [i for i, v in enumerate(lis, 1) if v == -1]
print(sum(lis[idx[0]:idx[1]-1]))
# 4
Demo
Here's an example that works without lambda
lis = [1,2,3,4,-1,1,1,1,1,-1,1,2,3]
first = lis.index(-1) + 1
second = lis[first:].index(-1) + first
result = sum(lis[first:second])
One approach is that you could create a boolean flag which sets to true when you see a -1 and set it back to false when you see the second -1 (or break). You add the numbers if the flag is true.
lis = [1,2,3,4,-1,1,1,1,1,-1,1,2,3]
sum = 0
flag = False;
for i in range(len(lis)):
if not flag:
if lis[i] == -1:
flag = True
elif lis[i] == -1:
flag = False #this line could be omitted
break
else:
sum += lis[i]
print(sum)
We can first compute the indexes where -1 appears:
In [12]: l = [1,2,3,4,-1,1,1,1,1,-1,1,2,3]
In [16]: indexes = [index for index in range(len(l)) if l[index] == -1]
In [17]: indexes
Out[17]: [4, 9]
Now, we know that -1 appears at indexes 4 & 9. To verify that we have the right set of numbers:
In [20]: l[indexes[0]:indexes[1]]
Out[20]: [-1, 1, 1, 1, 1]
So, computing the sum is easier now:
In [19]: sum(l[indexes[0]:indexes[1]])
Out[19]: 3
Did you mean this?
sum(filter(lambda n: -1 <= n <= 1, lis))
or without lambda:
def f(n):
return -1 <= n <= 1
sum(filter(f, lis))
You can use lis.index to find the first -1. It also offers a second parameter for where to start the search, so you can also use it to find the second -1. Then just get the slice between them and sum it.
>>> start = lis.index(-1) + 1
>>> stop = lis.index(-1, start)
>>> sum(lis[start:stop])
4

Python function that returns True or False if the inputted matrix is a magic square without using numpy [duplicate]

This question already has an answer here:
Writing a function that returns boolean true if matrix forms a magic square without importing numpy
(1 answer)
Closed 6 years ago.
I have two functions, one which is below:
def is_square(m):
for i in range(len(m)):
if len(m[i]) != len(m):
return False
return True
This one returns True if m is a square matrix, otherwise, it returns False. The problem is not with this one, it's with the 2nd function.
The second function:
def magic(m):
if(not(is_square(m))):
return False
# Here's where code starts.
This is what I attempted. EDIT: My second attempt after the feedback.
square = []
for i in range(len(m)):
square.append([])
for j in range(len(m)):
square[i].append(0)
total = 0
for i in range(len(m)-1):
total += square[i][i]
if total != x*(x*x+1)/2:
return False
else:
return True
total = 0;
for i in range(x):
total += square[i][x-1-i]
if total != x*(x*x+1)/2:
return False
else:
return True
Here are the expected outcomes of this function:
# this should print True
m0=[[2,7, 6],[9,5,1],[4,3,8]]
print(magic(m0))
# this should print True
m1 = [[16,3,2,13], [5,10,11,8],[9,6,7,12], [4,15,14,1]]
print(magic(m1))
# this should print False.
m2 = [[1,2,3,4], [5,6,7,8],[9,10,11,12], [13,14,15,16]]
print(magic(m2))
#this should print False.
m3 = [[1,1],[1,1]]
print(magic(m3))
#this should print False.
m3 = [[1,1],[1,1],[1,2]]
print(magic(m3))
By the way, I'm having a hard time installing numpy, so if there's other ways without import numpy, it would be awesome.
There seem to be a couple of errors in your original code. Mostly relating to the for loops, and ensuring that they start and stop in the right places (controlled by indentation in python).
Also you are testing for exact equality of numbers, which in the example is probably safe as you're dealing with integers, but can be an issue as numbers cannot be represented exactly as floating points.
As an example typing 1.1*3 == 3.3 returns False in python.
I have replaced your equality tests with math.isclose() tests from math module (I think this is only available in python 3, but not sure).
I have also added tests to check that the rows and columns all add-up as required:
import math
def is_square(m):
for i in range(len(m)):
if len(m[i]) != len(m):
return False
return True
def magic(m):
if(not(is_square(m))):
return False
total = 0
x = len(m)
for i in range(x):
total += m[i][i]
if not(math.isclose(total, x*(x*x+1)/2)):
return False
total = 0
for i in range(x):
total += m[i][x-1-i]
if not(math.isclose(total, x*(x*x+1)/2)):
return False
# Check rows all add-up
for i in range(x):
total = 0
for j in range(x):
total += m[i][j]
if not(math.isclose(total, x*(x*x+1)/2)):
return False
# Check cols all add-up
for i in range(x):
total = 0
for j in range(x):
total += m[j][i]
if not(math.isclose(total, x*(x*x+1)/2)):
return False
return True
# this should print True
m0=[[2,7,6],[9,5,1],[4,3,8]]
print(magic(m0))
# this should print True
m1 = [[16,3,2,13], [5,10,11,8],[9,6,7,12], [4,15,14,1]]
print(magic(m1))
# this should print False.
m2 = [[1,2,3,4], [5,6,7,8],[9,10,11,12], [13,14,15,16]]
print(magic(m2))
#this should print False.
m3 = [[1,1],[1,1]]
print(magic(m3))
#this should print False.
m4 = [[1,1],[1,1],[1,2]]
print(magic(m4))
Returns:
True
True
False
False
False

Find permutation list

I have a task. I know this task is really easy but..
A non-empty zero-indexed array A consisting of N integers is given.
A permutation is a sequence containing each element from 1 to N once, and only once.
For example, array A such that:
A[0] = 4
A[1] = 1
A[2] = 3
A[3] = 2
is a permutation, but array A such that:
A[0] = 4
A[1] = 1
A[2] = 3
is not a permutation.
The goal is to check whether array A is a permutation.
I implemented this solution, but I think this isn't the best solution.
def solution(A):
# write your code in Python 2.6
maxN = max(A)
B = list(xrange(1,maxN+1))
if sorted(A) == sorted(B):
return 1
else:
return 0
Do you have any ideas how I should solve this problem?
def solution(A):
N = len(A)
return min(A) == 1 and max(A) == N and len(set(A)) == N
That takes (expected) time linear in N, so is expected to be faster than sorting. But it does rely on the stated assumption that all list entries are in fact integers. If they're not, then, for example,
>>> solution([1, 2, 4, 3.14159])
True
If both arrays should have all numbers from 1 to N you shouldn't sort them, all you need to do is make sure they actually have all the numbers.
so this is your algorithm (working solution soon):
make sure the list is of size N, otherwise return false.
generate list of N zeros (We will refer to it as zero-list)
for each member (say it's value is m) of the list (both) increase the zero-list[m-1] by 1
make sure all members of zero-list is 1
This is O(n) as opposed to O(nlogn) that you have right now.
What you are doing verifies that each member from 1 to N exists in the list you're given
#!/usr/bin/env python
def is_perm(l, n):
# make sure initial criterias are met
if len(l) != max(l) or len(l) != n:
return False
# make room for a list that verifies existence from 1 to N
zero_list = [0 for i in l]
# "mark" using the new list each member of the input list
for i in l:
try:
zero_list[i-1] += 1
except:
return False
# make sure all members have been "marked"
for i in zero_list:
if zero_list[i] != 1:
return False
# if all is good, the earth is saved
return True
if "__main__" == __name__:
print is_perm([1, 2, 3, 3], 4) # false
print is_perm([1, 2, 4, 3], 4) # true
print is_perm([1, 2, 4, 300000000000000], 4) # false
def is_perm(lst):
n = len(lst)
if min(lst) != 1 or max(lst) != n:
return False
cnt = [1] * n
for e in lst:
cnt[e - 1] -= 1
return not any(cnt)
It has a worst case complexity O(n) which is of course optimal.
Just check if all elements are present ...
In [36]: all(map(lambda p: p in [1,4,3,2], range(1,5)))
Out[36]: True
In [37]: all(map(lambda p: p in [1,4,3,2444], range(1,5)))
Out[37]: False
In [38]: all(map(lambda p: p in [1,4,3], range(1,5)))
Out[38]: False
So I found solution which works great:
def solution(A):
A.sort(reverse=True)
return 1 if A[0] == len(A) and len(set(A)) == len(A) else 0
What about this?:
>>> def is_permutation(a, n):
if len(a) != n: return False
h = {}
for i in a:
if not 1 <= i <= n: return False
if h.setdefault(i, False): return False
h[i] = True
return True
>>> is_permutation([1,4,2,3], 4)
True
>>> is_permutation([1,4,2,0], 4)
False
>>> is_permutation([1,4,2],4)
False
Here is fastest way:
def solution(A):
'''
>>> solution([4,1,3,2])
1
>>> solution([2,3])
0
'''
suma = sum(A)
N = len(A)
if (N*(N+1)/2)!=suma:
return 0
return 1

how do you know if your list is ascending in python [duplicate]

This question already has answers here:
Pythonic way to check if a list is sorted or not
(27 answers)
Closed 9 years ago.
I wrote this program in python to see if a list is ascending and its not working, can someone help me?
list1 = [1, 2, 3, 4]
print (list1)
length = len(list1)
run_started = False
for x in range(length - 1):
t = list1[x + 1] - list1[x]
if t > 0 :
if run_started:
run_length = x
else:
run_started = True
run_length = x
else:
if run_started:
print (True)
print ("Run Length: {0}".format(run_length))
break
if not run_started:
print (False)
I'd say the easiest (although not the most efficient) way would be:
list1 = [3, 1, 2, 4]
if sorted(list1) == list1:
print "list1 is sorted"
Well, here's my go at it. Some have suggested sorting the list, which would be O(nlogn). I propose a simpler O(n) solution
def isAscending(list):
previous = list[0]
for number in list:
if number < previous:
return False
previous = number
return True
How about a one-liner to tell if every number in the list x is strictly increasing?
[(x[k+1]-x[k])>0 for k in range(len(x)-1)].count(True) == len(x)-1
I think the OP is asking what is wrong with their own code. If that's the case, here goes:
It looks like you never reach the end condition that you want. I mean, you get your run_started variable to get to True. But then what? Nothing else happens in your code since you never trigger the else statement that is contrary to your if t > 0 statement. I think you should re-think the logic in your code and what you want it to do exactly
EDIT: your code commented, I've put numbers in {{}} to show what happens in what order
list1 = [1, 2, 3, 4]
print (list1)
length = len(list1)
run_started = False
for x in range(length - 1): # Loop begins {{1}}
t = list1[x + 1] - list1[x]
if t > 0 :
if run_started:
run_length = x #You keep setting a new run_length {{3}}
else:
run_started = True #You've set run_started {{2}}
run_length = x
else:
if run_started:
print (True)
print ("Run Length: {0}".format(run_length))
break
if not run_started: #Then this is called after the loop {{4}} but it doesn't return true
print (False)
As you can see, you exit the for loop without ever calling else on line 13. Furthermore then final if not run_started is also never called. Your code works the way it is designed to work, though maybe not the way you want it to work. HTH
A way that is more efficient than fully constructing the sorted list (and should work for arbitrary iterable types, containing any data types that allow for greater-than comparisons):
def len_ascending_run_from_start(seq):
vals = enumerate(seq)
try:
c,x = 1, vals.next()[1]
except StopIteration:
raise ValueError("Sequence is empty!")
for i, cur_x in vals:
if cur_x < x:
break
c,x = c+1, cur_x
return c
E.g.:
In [44]: len_ascending_run_from_start([datetime.date(2012,1,4), datetime.date(2012,1,3), datetime.date(2012,1,5)])
Out[44]: 1
In [45]: len_ascending_run_from_start([datetime.date(2012,1,4), datetime.date(2012,1,6), datetime.date(2012,1,5)])
Out[45]: 2
In [46]: len_ascending_run_from_start([datetime.date(2012,1,4), datetime.date(2012,1,6), datetime.date(2012,1,7)])
Out[46]: 3
In [47]: len_ascending_run_from_start((1,2,3,4))
Out[47]: 4
In [48]: len_ascending_run_from_start((1,3,2,4))
Out[48]: 2
In [49]: len_ascending_run_from_start(set([1,3,2,4]))
Out[49]: 4
It could also be fun / useful to make a class such that len automatically reports this statistic about the underlying sequence (and keeps a simplistic cache of the result, to avoid calculating it repeatedly).
class AscendingRunFromStart(object):
def __init__(self, seq):
self.seq = seq
def __repr__(self):
return self.seq.__repr__()
__str__ = __repr__
def __len__(self):
if hasattr(self, "_len"):
return self._len
vals = enumerate(self.seq)
c,x = 1, vals.next()[1]
for i, cur_x in vals:
if cur_x < x:
break
c,x = c+1, cur_x
self._len = c
return self._len
E.g.:
In [76]: x = AscendingRunFromStart([1,3,2,4])
In [77]: x
Out[77]: [1, 3, 2, 4]
In [78]: len(x)
Out[78]: 2
A good extension would be to use a Descriptor pattern to make the seq attribute of the class read-only, or to invoke an updated len calculation whenever set is called. (Left as exercise for the reader...)

Categories