Finding item at index i of an iterable (syntactic sugar)? - python-3.x

I know that maps, range, filters etc. in python3 return iterables, and only calculate value when required. Suppose that there is a map M. I want to print the i^th element of M.
One way would be to iterate till i^th value, and print it:
for _ in range(i):
next(M)
print(next(M))
The above takes O(i) time, where I have to find the i^th value.
Another way is to convert to a list, and print the i^th value:
print(list(M)[i])
This however, takes O(n) time and O(n) space (where n is the size of the list from which the map M is created). However, this suits the so-called "Pythonic way of writing one-liners."
I was wondering if there is a syntactic sugar to minimise writing in the first way? (i.e., if there is a way which takes O(i) time, no extra space, and is more suited to the "Pythonic way of writing".)

You can use islice:
from itertools import islice
i = 3
print(next(islice(iterable), i, i + 1))
This outputs '3'.
It actually doesn't matter what you use as the stop argument, as long as you call next once.

Thanks to #DeepSpace for the reference to the official docs, I found the following:
from more_itertools import nth
print(nth(M, i))
It prints the element at i^th index of the iterable.

Related

Python list slice [0:-1:-1]

I ran into this statement while I was coding:
l = [1,2,3]
print(l[0:-1:-1])
I was expecting this piece of code gives me [1] however it gives me [], makes me think I must have mis-understood python slice operation, can someone explain what is going on here?
In a slice,
The first integer is the index where the slice starts.
The second integer is the index where the slice ends.
The third integer specifies a stride or step causing the resulting slice to skip items. -1 for reverse the output.
l[0:-1:-1]
is equivalent to
l[len(l)-1:len(l)-1:-1]
The first index converted 0 to len(l)-1, because you added -1 in the last index to reverse the list. This will always give you an empty list.
When you use slice in python and you type
l[x:y:-1]
it would somehow be equivalent to
l.reverse()
print(l[y:x])
l.reverse()
but with the difference that -1 reverses the list elements with their indexes
so if you type
l=[1, 2, 3]
l[2:0:-1]
the output will be
[3, 2]
The reason for empty list is that you change the order of indexes so it wont find any element in that window...
I gathered some information after talking with friends about this problem, now we kind of believe this is what happened: when I do l[0:-1:-1], the first thing interpreter will do is to convert that second -1 to the positive index, which is 2 in my case. Then it will iterate backward with the terminating condition being "start <= end", in this case since at the very beginning it will find 0 <= 2, so it will directly terminate, results in the output array being empty.
I didn't really get what the two other answers are saying here (silly me), maybe they are right, I need to look into the python source code for a 100% certain explanation, but for now I believe what I just stated here is the case.

Getting the nth values from a list to run through a list without a for-loop

list_ contains many integers within it, I want to get the nth value of it. The nth values are contained in the list_ var. So I would like to print list_[10], list_[25], list_[45]..... Is there a way that I could do this without using a for-loop, using the range function within a list perhaps list_[:]
list_ = [ 5268, 6760, 6761 ... 15149, 15150, 15151]
list_2= [10,25,45,60,90]
I think you can't do it only with range function.
The easiest way is this one:
result = [list_[i] for i in list_2]
print(result)
But here is some other ways: https://blog.finxter.com/python-list-arbitrary-indices/
The best method to use in this case is recursion with the help of slicing. Any iteration task can be performed using recursion and since performance drawback is insignificant for this particular question, it makes sense to use recursion.
Say we have two lists list_1 and list_2
def rec_increment(list_2,list_1):
if len(list_2) == 0:
return "" #so that it doesn't print 'none' in the end
else:
print(list_1[list_2[0]])
return rec_increment(list_2[1:],list_1) #only recur on the 2nd-nth part of the list
list_1= [0,10,20,30,40,50,60,70,80,90,100]
list_2= [1,2,4,5]
rec_increment(list_2,list_1) #gives 10 20 40 50
You can also make use of forEach() in java or even a while loop if the condition is only to not use a for-loop.

What is the Efficient way to right rotate list circularly in python without inbuilt function

def circularArrayRotation(a, k, queries):
temp=a+a
indexToCountFrom=len(a)-k
for val in queries:
print(temp[indexToCountFrom+val])
I am having this code to perform the rotation .
This function takes list as a, the number of time it needs to be rotated as k, and last is query which is a list containing indices whose value is needed after the all rotation.
My code works for all the cases except some bigger ones.
Where i am doing it wrong ?
link: https://www.hackerrank.com/challenges/circular-array-rotation/problem
You'll probably run into a timeout when you concatenate large lists with temp = a + a.
Instead, don't create a new list, but use the modulo operator in your loop:
print(a[(indexToCountFrom+val) % len(a)])

On a dataset made up of dictionaries, how do I multiply the elements of each dictionary with Python'

I started coding in Python 4 days ago, so I'm a complete newbie. I have a dataset that comprises an undefined number of dictionaries. Each dictionary is the x and y of a point in the coordinates.
I'm trying to compute the summatory of xy by nesting the loop that multiplies xy within the loop that sums the products.
However I haven't been able to figure out how to multiply the values for the two keys in each dictionary (so far I only got to multiply all the x*y)
So far I've got this:
If my data set were to be d= [{'x':0, 'y':0}, {'x':1, 'y':1}, {'x':2, 'y':3}]
I've got the code for the function that calculates the product of each pair of x and y:
def product_xy (product_x_per_y):
prod_xy =[]
n = 0
for i in range (len(d)):
result = d[n]['x']*d[n]['y']
prod_xy.append(result)
n+1
return prod_xy
I also have the function to add up the elements of a list (like prod_xy):
def total_xy_prod (sum_prod):
all = 0
for s in sum_prod:
all+= s
return all
I've been trying to find a way to nest this two functions so that I can iterate through the multiplication of each x*y and then add up all the products.
Make sure your code works as expected
First, your functions have a few mistakes. For example, in product_xy, you assign n=0, and later do n + 1; you probably meant to do n += 1 instead of n + 1. But n is also completely unnecessary; you can simply use the i from the range iteration to replace n like so: result = d[i]['x']*d[i]['y']
Nesting these two functions: part 1
To answer your question, it's fairly straightforward to get the sum of the products of the elements from your current code:
coord_sum = total_xy_prod(product_xy(d))
Nesting these two functions: part 2
However, there is a much shorter and more efficient way to tackle this problem. For one, Python provides the built-in function sum() to sum the elements of a list (and other iterables), so there's no need create total_xy_prod. Our code could at this point read as follows:
coord_sum = sum(product_xy(d))
But product_xy is also unnecessarily long and inefficient, and we could also replace it entirely with a shorter expression. In this case, the shortening comes from generator expressions, which are basically compact for-loops. The Python docs give some of the basic details of how the syntax works at list comprehensions, which are distinct, but closely related to generator expressions. For the purposes of answering this question, I will simply present the final, most simplified form of your desired result:
coord_sum = sum(e['x'] * e['y'] for e in d)
Here, the generator expression iterates through every element in d (using for e in d), multiplies the numbers stored in the dictionary keys 'x' and 'y' of each element (using e['x'] * e['y']), and then sums each of those products from the entire sequence.
There is also some documentation on generator expressions, but it's a bit technical, so it's probably not approachable for the Python beginner.

Why map is not executing a function in python 3

I have written a below small python program
def abc(x):
print(x)
and then called
map(abc, [1,2,3])
but the above map function has just displayed
<map object at 0x0000000001F0BC88>
instead of printing x value.
I know map is an iterator in python 3, but still it should have printed the 'x' value right. Does it mean that abc(x) method is not called when we use "map"?
The map iterator lazily computes the values, so you will not see the output until you iterate through them. Here's an explicit way you could make the values print out:
def abc(x):
print(x)
it = map(abc, [1,2,3])
next(it)
next(it)
next(it)
The next function calls it.__next__ to step to the next value. This is what is used under the hood when you use for i in it: # do something or when you construct a list from an iterator, list(it), so doing either of these things would also print out of the values.
So, why laziness? It comes in handy when working with very large or infinite sequences. Imagine if instead of passing [1,2,3] to map, you passed itertools.count() to it. The laziness allows you to still iterate over the resulting map without trying to generate all (and there are infinitely many) values up front.
lazy-evaluation
map(or range, etc.) in Python3 is lazy-evaluation: it will evaluate when you need it.
If you want a result of map, you can use:
list(map(abc, [1,2,3]))

Resources