Explanation of Python code - integers split - python

RTX_number = [int(x) for x in input().split()]
Could someone explain this line of code to me step by step?
I am having great difficulty understanding it.
As far as I know, .split creates spaces between elements?
I saw this code on a forum and I am trying to get a better understanding of it because I think it might be helpful for a simulation project.
I heard this is called a list comprehension, but I am kind of lost as of for now.

input().split()
Reads a line and breaks it where ever there is a space into a list of strings.
for x in input().split()
Takes this list, runs over it item by item, and binds this item to x.
int(x) for ...
Takes this x we bound, and runs int(x) on it and returns it.
[int(x) for x in input().split()]
Takes all these results and puts them into a list.

The short version is that this:
RTX_number = [int(x) for x in input().split()]
is a short-form of this:
RTX_number = []
for x in input().split():
RTX_number.append(int(x))
where input().split() returns the list of strings that you get from separating whatever input() returned on each whitespace (for example, "Hello World" becomes ["Hello", "World"].
The str.split() function can also be given an argument, such as ',', which it will split on instead of whitespace.
The general syntax of a comprehension is
(expression) for (element) in (iterable) if (condition)
For every element element in the iterable, if the condition resolves to True (note that the condition can be omitted entirely) the expression is evaluated and added to the returned list.
We usually use comprehensions as shorthand for full loops, since they often save space and complexity.
Note that list comprehensions aren't the only kind of comprehension - they can be used to make several different data structures:
# list comprehension - produces a list
[expression for element in iterable]
# set comprehension - produces a set instead of a list
{expression for element in iterable}
# dict comprehension - produces a dict with key-value pairs
{key:value for element in iterable}
# generator comprehension - like a list comprehension, but each expression is not
# actually evaluated until something tries to read it.
# The parentheses are technically optional, if the syntax isn't ambiguous
(expression for element in iterable)

This code is equivalent to:
# ask user input (it expected something like "1 2 34 5")
input_text = input()
# split on spaces
split_text_list = input_text.split()
list_of_integers = []
# for each string item in list
for item in split_text_list:
# convert to integer
number = int(item)
# add to list
list_of_integers.append(number)
But of course it avoids having all the unnecessary intermediate variables, so it is shorter. Also faster as it doesn't require to store the intermediate values.

Related

Building a list by input() python without setting a number of elements

i study python on my own in the middle of an ocean with limited access to internet.
I'm thinking of a way to make a list by input() without setting a number of elements in the beginning.
So far i end up with this:
list = []
value = None
while value != '':
value = input()
list.append(value)
if value == '':
del list[-1]
break
print(list)
As i can see, code works fine, i can create a list by input(), but it seems ugly to me.
I found the way 'With handling exception', but it works only for string or int.
Thank you!
Here is a way I would write it:
lst = list()
while True:
value = input()
if value == "":
break
lst.append(value)
First, use while True to loop forever, with an intention of breaking when certain input is encountered. When value is read, check if it is empty. If so, break. Otherwise, append value to lst and continue with the loop.
By the way, I renamed list to lst to avoid variable shadowing.
Can be written more compactly using the walrus operator (assignment with value):
li = list()
while (val := input()):
li.append(val)
This saves the input into val and simultaneously evaluates whether it's empty or not, breaking the loop in the former case. It uses the fact that empty strings evaluate to False.
So, assignment expressions were added for this very sort of pattern:
data = []
while (value:= input()):
data.append(value)
Note the assignment expression "walrus operator" := is only available in Python >= 3.8
Otherwise, you'd generally do something like:
data = []
value = input()
while value:
data.append(value)
value = input()
well if you want users to input the element multiple times then the above answers are good.
But just say you want an input of elements using a specific separator(space or comma etc) you can do this in one line.
eg. if you were to take input using a space as separator,
l = [x for x in input().split()] would build your list and
if you were to take input and keep , as a separator you could do something like
l = [x for x in input().split(sep=",")].

what's the difference between filter and comprehention with if?

def anagramwordchecker(z,w):
if sorted([x for x in w])==sorted([x for x in z]):return True
return False
def anagramlistchecker(l,w):
d={}
for x in w:
d.update({x:w.count(x)})
l=list(filter(lambda x:anagramwordchecker(x,w),l))
return l
print(anagramlistchecker(['bcda', 'abce', 'cbda', 'cbea', 'adcb'],'abcd'))
trying to check which words are anagram.
using both of this it will print the same:
l=[x for x in l if anagramwordchecker(x,w)]
l=list(filter(lambda x:anagramwordchecker(x,w),l))
and it will be:
['bcda', 'cbda', 'adcb']
then what's the difference? any advantage using filter? cause comprehension is easier.
If you print the results of the following example, you will know which one is faster (Comments are results I got).
timeit.Timer('''[x for x in range(100) if x % 2 == 0]''' ).timeit(number=100000)
timeit.Timer('''list(filter(lambda x: x % 2 == 0, range(100)))''').timeit(number=100000)
# 0.3664856200000486
# 0.6642515319999802
So in your case, list comprehension would be faster. But let's see the following example.
timeit.Timer('''[x for x in range(100) if x % 2 == 0]''' ).timeit(number=100000)
timeit.Timer('''(x for x in range(100) if x % 2 == 0)''' ).timeit(number=100000)
timeit.Timer('''filter(lambda x: x % 2 == 0, range(100))''').timeit(number=100000)
# 0.5541256509999357
# 0.024836917000016
# 0.017953075000036733
The results show that casting an iterable to list takes much time and filter is faster than generator expression. So if your result does not really have to be a list, returning an iterable in a timely manner would be better.
As stated in here,
Note that filter(function, iterable) is equivalent to the generator expression (item for item in iterable if function(item)) if function is not None and (item for item in iterable if item) if function is None.
But list comprehension can do much more than simply filtering. If filter is given to the interpreter, it will knows it is a filter function. However, if a list comprehension is given to the interpreter, the interpreter does not know what it really is. After taking some time interpreting the list comprehension to something like a function, it would be a filter or filterfalse function in the end. Or, something else completely different.
filter with not condition can do what filterfalse does. But filterfalse is still there. Why? not operator does not need to be applied.
There is no magic. Human-friendly 1-for-many grammars are based on encapsulation. For them to be machine-executable binaries, they need to be decapsulated back and it takes time.
Go with a specific solution if it is enough than taking a more general solutions. Not only in coding, general solutions are usually for convenience, not for best results.

How to return a list that is made up of extracted elements from another list in python?

I am building a function to extract all negatives from a list called xs and I need it to add those extracted numbers into another list called new_home. I have come up with a code that I believe should work, however; it is only showing an empty list.
Example input/output:
xs=[1,2,3,4,0,-1,-2,-3,-4] ---> new_home=[1,2,3,4,0]
Here is my code that returns an empty list:
def extract_negatives(xs):
new_home=[]
for num in range(len(xs)):
if num <0:
new_home= new_home+ xs.pop(num)
return
return new_home
Why not use
[v for v in xs if v >= 0]
def extract_negatives(xs):
new_home=[]
for num in range(len(xs)):
if xs[num] < 0:
new_home.append(xs[num])
return new_home
for your code
But the Chuancong Gao solution is better:
def extract_negative(xs):
return [v for v in xs if v >= 0]
helper function filter could also help. Your function actually is
new_home = filter(lambda x: x>=0, xs)
Inside the loop of your code, the num variable doesn't really store the value of the list as you expect. The loop just iterates for len(xs) times and passes the current iteration number to num variable.
To access the list elements using loop, you should construct loop in a different fashion like this:
for element in list_name:
print element #prints all element.
To achieve your goal, you should do something like this:
another_list=[]
for element in list_name:
if(element<0): #only works for elements less than zero
another_list.append(element) #appends all negative element to another_list
Fortunately (or unfortunately, depending on how you look at it) you aren't examining the numbers in the list (xs[num]), you are examining the indexes (num). This in turn is because as a Python beginner you probably nobody haven't yet learned that there are typically easier ways to iterate over lists in Python.
This is a good (or bad, depending on how you look at it) thing, because had your code taken that branch you would have seen an exception occurring when you attempted to add a number to a list - though I agree the way you attempt it seems natural in English. Lists have an append method to put new elements o the end, and + is reserved for adding two lists together.
Fortunately ignorance is curable. I've recast your code a bit to show you how you might have written it:
def extract_negatives(xs):
out_list = []
for elmt in xs:
if elmt < 0:
out_list.append(elmt)
return out_list
As #ChuangongGoa suggests with his rather terse but correct answer, a list comprehension such as he uses is a much better way to perform simple operations of this type.

Python nested forloop list comprehension

I'm trying to convert this working nested forloop into a single line list comprehension & i cannot seem to get it to work. The pseudo-code is as follows:
result = []
for x in something:
for y in x.address:
m = re.search("some pattern to match",y)
if m:
result += [m.group(1)]
Any pointers on how do i go about this ?
You'll need a generator expression..
matches = ( re.search(r'some pattern to match', y) for x in something
for y in x.address )
result = [ m.group(1) for m in matches if m ]
Nested loops are not really a problem for list comprehensions, as you can nest those there too:
lst = []
for y in z:
for x in y:
lst.append(f(x))
This translates into the following list comprehension:
[f(x) for y in z for x in y]
And you can easily continue that for multiple levels.
Conditions that decide on whether you want to add something to the list or not also work just fine:
lst = []
for x in y:
if t(x):
lst.append(f(x))
This translated into the following list comprehension with a filter:
[f(x) for x in y if t(x)]
Of course you can also combine that with multiple levels.
Now what is some kind of a problem though is when you want to execute something first, then filter on the result of that and append also something that depends on the result. The naive solution would be to move the function call inside and do it twice:
rexpr = re.compile('some pattern to match')
[rexpr.search(y).group(1) for x in something for y in x.address if rexpr.search(y)]
But this obviously runs the search twice which you generally want to avoid. At this point, you could use some hackish solutions which I generally wouldn’t recommend (as they harm readability). Since your result only depends on the result of the regular expression search, you could also solve this in two steps: First, you search on every element and map them to a match object, and then you filter on those matches and just return the valid ones:
[m.group(1) for m in (rexpr.search(y) for x in something for y in x.address) if m]
Note that I’m using generator expressions here: Those are essentially the same as list comprehensions, but don’t create the full result as a list but only yield on element at a time. So it’s more efficient if you only want to consume this one by one (which is the case here). After all, you’re only interested in the result from the list comprehension, so the comprehension will consume the generator expression.
I would do something like this:
# match function
def match(x):
m = re.search("some pattern to match",x)
if m:
return m.group(1)
else:
return None
#list comprehension
results = [match(y) for x in something for y in x.address if match(y)]

For loop variable in Python

Can anyone explain how x is taking integer values. We are directly using x in for loop "for x in a"
How is the compiler going to recognize it that x represents the strings inside the list?
>>> # Measure some strings:
... a = ['cat', 'window', 'defenestrate']
>>> for x in a:
... print x, len(x)
...
cat 3
window 6
defenestrate 12
for works differently in Python than it works in languages like C. Instead of counting up/down a numerical value and checking an end condition as you usually would in C:
for (i=0; i<=max; i++) do_something();
it iterates over all the elements in the container (whose name is referenced after the in):
for item in iterable:
do_something(item)
Its precise behavior depends on the type of container (iterable) used; in a list or tuple, it will start at the first element, then move through the list/tuple one item at a time until the final element has been reached. Each of the elements will be then referenced by a name (item in this example) so that it can be operated on in the body of the loop.
In a dictionary, for would iterate through the dictionary's keys (in an unspecified order), so item would contain a key of the dictionary.
In a string, it iterates through the letters of the string, one by one. Etc.
how X is taking integer values
It's not. It is taking the successive values contained in the sequence you're iterating over, which is this case are strings.
The elements don't have to be of a particular type, nor do they even have to be of the same type.
To be a little bit more technical, the for loop iterates over an iterator provided by an iterable.
An iterable can be a list, a string, a tuple etc., an iterator is an object used for iteration.
With for i in a:, you request for an iterator for a, exactly the way you do with iter(a).
This happens
either by calling the_iterator = a.__iter__()
or, if that doesn't work, but a has a __getitem__(), by calling this with successively growing indexes until IndexError is raised.
This interator is then called .next() (.__next__() in Python 3) on each loop run until the iterator is exhausted and raises StopIteration.
So, in other words:
for x in a: print x, len(x)
internally works like
a_iter = iter(a)
while True:
try: x = next(a)
except StopIteration: break
print x, len(x)
but looks much nicer.

Categories