C++ nested for loops representation in Python - python

I have been coding in C++ and Java for some time. I have started to code in Python recently as well. However, I got stuck in the case of nested for loops in Python.
I have written following code in C++. What will be the equivalent code of it in Python?
for(int i = 0; i<a.size();i++){
for(int j = i; j<a.size();j++)
{
if a[i] != a[j]
/*some code */
}
}
I tried to use enumerate as follows, but it fails:
for i, val in enumerate(lst):
for j=i,val2 in enumerate(lst):
if val != val2
#some code
So how can I represent the C++ nested loops in python?

import itertools
for val1, val2 in itertools.combinations(lst, 2):
if val1 != val2:
combinations will loop over all cases of choosing two distinct elements from your list which is what your nested for loops are doing anyhow. Note that your second nested for loop is initialized at j=i, but that first case will always fail to process anyhow because it will never pass the conditional.
If you really, really need the indices, and usually you shouldn't, you can do:
for (i, val1), (j, val2) in itertools.combinations(enumerate(lst), 2):
if val1 != val2:

As mentioned elsewhere, enumerate does one thing (provide indexes). It will not truncate or skip around in your list. If you wanted to use enumerate, one option is to pass a list slice instead of the full list, and use the start= keyword argument to start the index numbering correctly:
for i, val in enumerate(lst):
for j, val2 in enumerate(lst[i:], start=i):
if val != val2:
#some code

The enumerate function doesn't have a start index, however range does in that sense. It should be noted that while enumerate(sequence, start=0) has a start parameter, it only specifies the start of the returned index, and not the first index of which the list is accessed.
So you could do it like this:
n = len(lst)
for i in range(n):
val = lst[i]
for j in range(i, n):
val2 = lst[j]
if val != val2:
#some code

Related

Why swapping does not occur in below python code

def rev(n):
for i in range(int(len(n)//2)):
temp = n[i]
n[i] = n[len(n)-i-1]
n[len(n)-i-1] = temp
or,n[i], n[len(n)-i-1] = n[len(n)-i-1], n[i]
return n
n=[34,45,56,67]
print(rev(n))
Above code doesn't reverse the list even the logic is correct still the output is same as input.
Can anyone help me with that as i am little bit confused.
The intention appears to be to reverse the contents of a list in situ.
The most common way to do this is to create a new list with:
mylist[::-1]
...then... copy over the original like this:
mylist[:] = mylist[::-1]
However, the intent appears to be to use a custom loop to reverse in place.
def rev(_list):
i, j = 0, len(_list)
while (j := j - 1) > i:
_list[i], _list[j] = _list[j], _list[i]
i += 1
return _list
This demonstrates the correct element swap syntax and also obviates the need to create a new list. It is however very slow in comparison to traditional techniques

How can i know if a list is decreasing? (Python)

I am new to python and I have to do an exercise for classes. The exercises asks me to make a function which tells weather a list given is ordered decreasing or not (Giving back True or False)
I tried the following code:
def no_decreasing(list):
for num in len(list):
if list[num] <= list[num+1]:
check = bool(1)
else:
check = bool(0)
break
return check
It gives back an te error "int" object is not iterable in line 2, does anyone know why?
Note: don't use list as the parameter name (it's a builtin type), use something else. I'll use nums as the place of the list parameter rather than list.
The expression for num in len(nums) doesn't work because len(nums) is a single int. What you would want instead is for num in nums (which would iterate over each number in nums, or for index in len(range(nums)) (which would iterate over each valid index into nums).
Other options:
for i, num in enumerate(nums) -- i is the index, num is the value.
for num1, num2 in zip(nums, nums[1:]) -- num1 and num2 are two successive values from nums, obtained by zipping nums with a shifted version of itself.
Additional note: when you need a boolean literal, instead of bool(1) and bool(0) just use True and False!
You could also shortcut the entire problem by sorting the list in decreasing order and seeing if it's the same as the original list:
def is_decreasing(nums):
return nums == sorted(nums, reverse=True)
Well you are trying to iterate over indeces, so
for i in range(len(lst)): # never use "list" as a variable name
or rather
for i in range(len(lst)-1): # to avoid an index error for its right neighbor
would be appropriate. However, a better way would use zip
def non_decreasing(lst):
for a, b in zip(lst, lst[1:]):
if b < a:
return False
return True
A short-hand for that pattern is any or all:
def non_decreasing(lst):
return all(a <= b for a, b in zip(lst, lst[1:]))
# return not any(b < a for a, b in zip(lst, lst[1:]))
You are trying to get the index in the for loop, but you've made a semantic mistake:
for num in len(list):
# This does not work. It can not iterate through an integer.
len() function returns an integer. Your basically saying for num in 10, say if the list has 10 numbers.
What you want is the range function:
for num in range(0, len(list)):
This will loop from num=0 to num=0+len(list)-1.
Be careful though with if list[num] <= list[num+1]:, as the previous approach will make that line search for an index greater them your array size. As such, this is how you could fix your code:
for num in range(0, len(list)-1):
P.S.: There are other ways to solve that issue, but since it is a class exercise, I've focused on solving the issue you've had when iterating through an integer.
Others have pointed out using zip(lst, lst[1:]). This is undesirable for large lists, though, since you first have to make a copy of lst (minus the first element) before zip can produce the pairwise iterator that the for loop uses.
Instead, use two separate iterators, advancing the second one before passing it to zip.
def no_decreasing(lst):
i1 = iter(lst)
i2 = iter(lst)
next(i2)
return all(a >= b for a, b in zip(i1, i2))
# Or you can use map
# return all(map(operator.ge, i1, i2))

Function to check if the row of a matrix contains only zeros

My intention was to create (without the use of any module) a function which would index all zero rows of a matrix inside a list, here is the code I developed:
def check0(self):
L = []
for i in range(0, self._m):
for j in range(0, self._n):
if self[i, j] == 0:
if i not in L:
L.append(i)
return L
However at this point the function indexes the row as soon that it detects a zero in it, and I do not manage to find an additional condition for this to stop. Would anyone please have a solution?
The problem with your code is that it would add a row if at least one element of the row is zero. This would be a solution:
def check0(self):
L = []
for i in range(0, self._m):
for j in range(0, self._n):
if self[i, j] != 0:
break
else:
L.append(i)
return L
Here I am using the for else statement. The else clause is executed if the break statement inside the for is not reached, which only happens if all elements of the row are zero.
Assuming your previous questions deal with the same matrix class, you seem to store the data in a list of lists. In that case you can simply do
def check0(self):
return [i for i, row in enumerate(self._matrix) if not any(row)]
0 has a falsy value, so any(list_of_only_zeros) will return False.
If you wanted to implement the any() functionality yourself, it'd look like the following
indices = []
for i, row in enumerate(self._matrix):
contains_nonzero = False
for elem in row:
if elem != 0:
contains_nonzero = True
break
if not contains_nonzero:
indices.append(i)
Which is similar to the for else suggestion from the other answer. In this case the for else is a bit more succinct, since it saves you two lines not having to toggle the contains_nonzero flag.

Is there a shorter way to initialize this loop?

Is there a shorter way to initialize this loop?
It feels like typing "val" four times for such a simple statement might not be the fastest way to do it.
(The example is a random code for explaining my point, the actual loop content would be much more complex.)
values=[4,8,0,1,5,8,3]
for val in [val for val in values if val!=1]:
print(val)
Generator expression (no need to create yet another list to iterate over) and the filter() function (creates an iterator) come to mind:
values = [4,8,0,1,5,8,3]
# generator expression instead of list expressen - is more efficient
for val in (val for val in values if val != 1):
print(val)
# filter the list - creates an iterator
for val in filter(lambda x:x != 1, values):
print (val)
Output:
4
8
0
5
8
3

Python -- list comprehension with try/exception and nested conditional

This code should find the mode of a list in O(n) linear time. I want to turn this into a list comprehension because I'm teaching myself Python, and am trying to improve my list comprehension skills.
These were informative but don't really answer my question:
Convert nested loops and conditions to a list comprehension
`elif` in list comprehension conditionals
Nested list comprehension equivalent
The problem that I'm running into is nesting the if's and the try/except. I'm sure this is simple question so a junior Python programmer might have the answer quickly.
def mode(L):
# your code here
d = {}; mode = 0; freq = 0
for j in L:
try:
d[j] += 1
if d[j] > freq:
mode = j; freq = d[j]
except(KeyError): d[j] = 1
return mode
Note that L parameter is a list of ints like this:
L = [3,4,1,20,102,3,5,67,39,10,1,4,34,1,6,107,99]
I was thinking something like:
[try (d[j] += 1) if d[j] > freq (mode = j; freq = d[j]) except(KeyError): d[j] = 1 for j in L]
But I don't have enough duct tape to fix how badly the syntax is off with that thing.
I know you're learning comprehensions, but you can do this with a default dictionary, or a Counter too.
import collections
def mode(L):
# your code here
d = collections.defaultdict(lambda: 1); mode = 0; freq = 0
for j in L:
d[j] += 1
if d[j] > freq:
mode = j; freq = d[j]
return mode
Better still, when you are not trying to learn comprehensions:
import collections
def mode(L):
collections.Counter(L).most_common(1)[0][0]
While it might not be possible directly do this within a list comprehension, there's also no reason to. You only really want to be checking for errors when you're actually retrieving the results. As such, you really want to use a generator instead of a list comprehension.
Syntax is largely the same, just using parens instead instead of brackets, so you would do something like this:
generator = (do something)
try:
for thing in generator
except KeyError:
etc...
That said, you really don't want to do this for you particular application. You want to use a counter:
from collections import Counter
d = Counter(L)
mode = Counter.most_common(1)[0]
You can't incorporate try: except: in a list comprehension. However, you can get around it by refactoring into a dict comprehension:
d = {i: L.count(i) for i in L}
You can then determine the maximum and corresponding key in a separate test. However, this would be O(n**2).
It's not possible to use try-except expressions in list comprenhension.
Quoting this answer:
It is not possible to handle exceptions in a list comprehension for a list comprehension is an expression containing other expression, nothing more (i.e., no statements, and only statements can catch/ignore/handle exceptions).
Edit 1:
What you could do instead of using the try-except clause, is use the get method from the dictionary:
def mode(L):
d = {}
mode = 0
freq = 0
for j in L:
d[j] = d.get(j, 0) + 1
if d[j] > freq:
mode = j
freq = d[j]
return mode
From Python docs:
get(key[, default]): Return the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.
Edit 2:
This is my list comprenhension approach, not very efficient, just for fun:
r2 = max(zip(L, [L.count(e) for e in L]), key = lambda x: x[1])[0]
Since you're trying to find the value that appears most often, an easy way to do that is with max:
def mode(L):
return max(L, key=L.count)
This is a bit less efficient than the other answers that suggest using collections.Counter (it is O(N^2) rather than O(N)), but for a modest sized list it will probably be fast enough.

Categories

Resources