PYTHON How to continue code formatted by input result? [duplicate] - python

If I write
for i in range(5):
print i
Then it gives 0, 1, 2, 3, 4
Does that mean Python assigned 0, 1, 2, 3, 4 to i at the same time?
However if I wrote:
for i in range(5):
a=i+1
Then I call a, it only gives 5
But if I add ''print a'' it gives 1, 2, 3, 4, 5
So my question is what is the difference here?
Is i a string or a list or something else?
Or maybe can anyone help me to sort out:
for l in range(5):
#vs,fs,rs are all m*n matrixs,got initial values in,i.e vs[0],fs[0],rs[0] are known
#want use this foor loop to update them
vs[l+1]=vs[l]+fs[l]
fs[l+1]=((rs[l]-re[l])
rs[l+1]=rs[l]+vs[l]
#then this code gives vs,fs,rs
If I run this kind of code, then I will get the answer only when l=5
How can I make them start looping?
i.e l=0 got values for vs[1],fs[1],rs[1],
then l=1 got values for vs[2],rs[2],fs[2]......and so on.
But python gives different arrays of fs,vs,rs, correspond to different value of l
How can I make them one piece?

A "for loop" in most, if not all, programming languages is a mechanism to run a piece of code more than once.
This code:
for i in range(5):
print i
can be thought of working like this:
i = 0
print i
i = 1
print i
i = 2
print i
i = 3
print i
i = 4
print i
So you see, what happens is not that i gets the value 0, 1, 2, 3, 4 at the same time, but rather sequentially.
I assume that when you say "call a, it gives only 5", you mean like this:
for i in range(5):
a=i+1
print a
this will print the last value that a was given. Every time the loop iterates, the statement a=i+1 will overwrite the last value a had with the new value.
Code basically runs sequentially, from top to bottom, and a for loop is a way to make the code go back and something again, with a different value for one of the variables.
I hope this answered your question.

When I'm teaching someone programming (just about any language) I introduce for loops with terminology similar to this code example:
for eachItem in someList:
doSomething(eachItem)
... which, conveniently enough, is syntactically valid Python code.
The Python range() function simply returns or generates a list of integers from some lower bound (zero, by default) up to (but not including) some upper bound, possibly in increments (steps) of some other number (one, by default).
So range(5) returns (or possibly generates) a sequence: 0, 1, 2, 3, 4 (up to but not including the upper bound).
A call to range(2,10) would return: 2, 3, 4, 5, 6, 7, 8, 9
A call to range(2,12,3) would return: 2, 5, 8, 11
Notice that I said, a couple times, that Python's range() function returns or generates a sequence. This is a relatively advanced distinction which usually won't be an issue for a novice. In older versions of Python range() built a list (allocated memory for it and populated with with values) and returned a reference to that list. This could be inefficient for large ranges which might consume quite a bit of memory and for some situations where you might want to iterate over some potentially large range of numbers but were likely to "break" out of the loop early (after finding some particular item in which you were interested, for example).
Python supports more efficient ways of implementing the same semantics (of doing the same thing) through a programming construct called a generator. Instead of allocating and populating the entire list and return it as a static data structure, Python can instantiate an object with the requisite information (upper and lower bounds and step/increment value) ... and return a reference to that.
The (code) object then keeps track of which number it returned most recently and computes the new values until it hits the upper bound (and which point it signals the end of the sequence to the caller using an exception called "StopIteration"). This technique (computing values dynamically rather than all at once, up-front) is referred to as "lazy evaluation."
Other constructs in the language (such as those underlying the for loop) can then work with that object (iterate through it) as though it were a list.
For most cases you don't have to know whether your version of Python is using the old implementation of range() or the newer one based on generators. You can just use it and be happy.
If you're working with ranges of millions of items, or creating thousands of different ranges of thousands each, then you might notice a performance penalty for using range() on an old version of Python. In such cases you could re-think your design and use while loops, or create objects which implement the "lazy evaluation" semantics of a generator, or use the xrange() version of range() if your version of Python includes it, or the range() function from a version of Python that uses the generators implicitly.
Concepts such as generators, and more general forms of lazy evaluation, permeate Python programming as you go beyond the basics. They are usually things you don't have to know for simple programming tasks but which become significant as you try to work with larger data sets or within tighter constraints (time/performance or memory bounds, for example).
[Update: for Python3 (the currently maintained versions of Python) the range() function always returns the dynamic, "lazy evaluation" iterator; the older versions of Python (2.x) which returned a statically allocated list of integers are now officially obsolete (after years of having been deprecated)].

for i in range(5):
is the same as
for i in [0,1,2,3,4]:

range(x) returns a list of numbers from 0 to x - 1.
>>> range(1)
[0]
>>> range(2)
[0, 1]
>>> range(3)
[0, 1, 2]
>>> range(4)
[0, 1, 2, 3]
for i in range(x): executes the body (which is print i in your first example) once for each element in the list returned by range().
i is used inside the body to refer to the “current” item of the list.
In that case, i refers to an integer, but it could be of any type, depending on the objet on which you loop.

The range function wil give you a list of numbers, while the for loop will iterate through the list and execute the given code for each of its items.
for i in range(5):
print i
This simply executes print i five times, for i ranging from 0 to 4.
for i in range(5):
a=i+1
This will execute a=i+1 five times. Since you are overwriting the value of a on each iteration, at the end you will only get the value for the last iteration, that is 4+1.
Useful links:
http://www.network-theory.co.uk/docs/pytut/rangeFunction.html
http://www.ibiblio.org/swaroopch/byteofpython/read/for-loop.html

It is looping, probably the problem is in the part of the print...
If you can't find the logic where the system prints, just add the folling where you want the content out:
for i in range(len(vs)):
print vs[i]
print fs[i]
print rs[i]

Related

Python syntax for a map(max()) call

I came across this particular piece of code in one of "beginner" tutorials for Python. It doesn't make logical sense, if someone can explain it to me I'd appreciate it.
print(list(map(max, [4,3,7], [1,9,2])))
I thought it would print [4,9] (by running max() on each of the provided lists and then printing max value in each list). Instead it prints [4,9,7]. Why three numbers?
You're thinking of
print(list(map(max, [[4,3,7], [1,9,2]])))
# ^ ^
providing one sequence to map, whose elements are [4,3,7] and [1,9,2].
The code you've posted:
print(list(map(max, [4,3,7], [1,9,2])))
provides [4,3,7] and [1,9,2] as separate arguments to map. When map receives multiple sequences, it iterates over those sequences in parallel and passes corresponding elements as separate arguments to the mapped function, which is max.
Instead of calling
max([4, 3, 7])
max([1, 9, 2])
it calls
max(4, 1)
max(3, 9)
max(7, 2)
map() takes each element in turn from all sequences passed as the second and subsequent arguments. Therefore the code is equivalent to:
print([max(4, 1), max(3, 9), max(7, 2)])
It looks like this question has been answered already, but I'd like to note that map() is considered obsolete in python, with list comprehensions being used instead as they are usually more performant. Your code would be equivalent to print([max(x) for x in [(4,1),(3,9),(7,2)]]).
Also, here is an interesting article from Guido on the subject.
Most have answered OPs question as to why,
Here's how to get that output using max:
a = [4,3,7]
b = [1,9,2]
print(list(map(max, [a, b])))
gives
[7, 9]

Python - Count Elements in Iterator Without Consuming

Given an iterator it, I would like a function it_count that returns the count of elements that iterator produces, without destroying the iterator. For example:
ita = iter([1, 2, 3])
print(it_count(ita))
print(it_count(ita))
should print
3
3
It has been pointed out that this may not be a well-defined question for all iterators, so I am not looking for a completely general solution, but it should function as anticipated on the example given.
Okay, let me clarify further to my specific case. Given the following code:
ita = iter([1, 2, 3])
itb, itc = itertools.tee(ita)
print(sum(1 for _ in itb))
print(sum(1 for _ in itc))
...can we write the it_count function described above, so that it will function in this manner? Even if the answer to the question is "That cannot be done," that's still a perfectly valid answer. It doesn't make the question bad. And the proof that it is impossible would be far from trivial...
Not possible. Until the iterator has been completely consumed, it doesn't have a concrete element count.
The only way to get the length of an arbitary iterator is by iterating over it, so the basic question here is ill-defined. You can't get the length of any iterator without iterating over it.
Also the iterator itself may change it's contents while being iterated over, so the count may not be constant anyway.
But there are possibilities that might do what you ask, be warned none of them is foolproof or really efficient:
When using python 3.4 or later you can use operator.length_hint and hope the iterator supports it (be warned: not many iterators do! And it's only meant as a hint, the actual length might be different!):
>>> from operator import length_hint
>>> it_count = length_hint
>>> ita = iter([1, 2, 3])
>>> print(it_count(ita))
3
>>> print(it_count(ita))
3
As alternative: You can use itertools.tee but read the documentation of that carefully before using it. It may solve your issue but it won't really solve the underlying problem.
import itertools
def it_count(iterator):
return sum(1 for _ in iterator)
ita = iter([1, 2, 3])
it1, it2 = itertools.tee(ita, 2)
print(it_count(it1)) # 3
print(it_count(it2)) # 3
But this is less efficient (memory and speed) than casting it to a list and using len on it.
I have not been able to come up with an exact solution (because iterators may be immutable types), but here are my best attempts. I believe the second should be faster, according to the documentation (final paragraph of itertools.tee).
Option 1
def it_count(it):
tmp_it, new_it = itertools.tee(it)
return sum(1 for _ in tmp_it), new_it
Option 2
def it_count2(it):
lst = list(it)
return len(lst), lst
It functions well, but has the slight annoyance of returning the pair rather than simply the count.
ita = iter([1, 2, 3])
count, ita = it_count(ita)
print(count)
Output: 3
count, ita = it_count2(ita)
print(count)
Output: 3
count, ita = it_count(ita)
print(count)
Output: 3
print(list(ita))
Output: [1, 2, 3]
There's no generic way to do what you want. An iterator may not have a well defined length (e.g. itertools.count which iterates forever). Or it might have a length that's expensive to calculate up front, so it won't let you know how far you have to go until you've reached the end (e.g. a file object, which can be iterated yielding lines, which are not easy to count without reading the whole file's contents).
Some kinds of iterators might implement a __length_hint__ method that returns an estimated length, but that length may not be accurate. And not all iterators will implement that method at all, so you probably can't rely upon it (it does work for list iterators, but not for many others).
Often the best way to deal with the whole contents of an iterator is to dump it into a list or other container. After you're done doing whatever operation you need (like calling len on it), you can iterate over the list again. Obviously this requires the iterator to be finite (and for all of its contents to fit into memory), but that's the limitation you have to deal with.
If you only need to peek ahead by a few elements, you might be able to use itertools.tee, but it's no better than dumping into a list if you need to consume the whole contents (since it keeps the values seen by one of its returned iterators but another in a data structure similar to a deque). It wouldn't be any use for finding the length of the iterator.

Does range() really create lists?

Both my professor and this guy claim that range creates a list of values.
"Note: The range function simply returns a list containing the numbers
from x to y-1. For example, range(5, 10) returns the list [5, 6, 7, 8,
9]."
I believe this is to be inaccurate because:
type(range(5, 10))
<class 'range'>
Furthermore, the only apparent way to access the integers created by range is to iterate through them, which leads me to believe that labeling range as a lists is incorrect.
In Python 2.x, range returns a list, but in Python 3.x range returns an immutable sequence, of type range.
Python 2.x:
>>> type(range(10))
<type 'list'>
>>> type(xrange(10))
<type 'xrange'>
Python 3.x:
>>> type(range(10))
<class 'range'>
In Python 2.x, if you want to get an iterable object, like in Python 3.x, you can use xrange function, which returns an immutable sequence of type xrange.
Advantage of xrange over range in Python 2.x:
The advantage of xrange() over range() is minimal (since xrange() still has to create the values when asked for them) except when a very large range is used on a memory-starved machine or when all of the range’s elements are never used (such as when the loop is usually terminated with break).
Note:
Furthermore, the only apparent way to access the integers created by range() is to iterate through them,
Nope. Since range objects in Python 3 are immutable sequences, they support indexing as well. Quoting from the range function documentation,
Ranges implement all of the common sequence operations except concatenation and repetition
...
Range objects implement the collections.abc.Sequence ABC, and provide features such as containment tests, element index lookup, slicing and support for negative indices.
For example,
>>> range(10, 20)[5]
15
>>> range(10, 20)[2:5]
range(12, 15)
>>> list(range(10, 20)[2:5])
[12, 13, 14]
>>> list(range(10, 20, 2))
[10, 12, 14, 16, 18]
>>> 18 in range(10, 20)
True
>>> 100 in range(10, 20)
False
All these are possible with that immutable range sequence.
Recently, I faced a problem and I think it would be appropriate to include here. Consider this Python 3.x code
from itertools import islice
numbers = range(100)
items = list(islice(numbers, 10))
while items:
items = list(islice(numbers, 10))
print(items)
One would expect this code to print every ten numbers as a list, till 99. But, it would run infinitely. Can you reason why?
Solution
Because the range returns an immutable sequence, not an iterator object. So, whenever islice is done on a range object, it always starts from the beginning. Think of it as a drop-in replacement for an immutable list. Now the question comes, how will you fix it? Its simple, you just have to get an iterator out of it. Simply change
numbers = range(100)
to
numbers = iter(range(100))
Now, numbers is an iterator object and it remembers how long it has been iterated before. So, when the islice iterates it, it just starts from the place where it previously ended.
It depends.
In python-2.x, range actually creates a list (which is also a sequence) whereas xrange creates an xrange object that can be used to iterate through the values.
On the other hand, in python-3.x, range creates an iterable (or more specifically, a sequence)
range creates a list if the python version used is 2.x .
In this scenario range is to be used only if its referenced more than once otherwise use xrange which creates a generator there by redusing the memory usage and sometimes time as it has lazy approach.
xrange is not there in python 3.x rather range stands for what xrange is for python 2.x
refer to question
What is the difference between range and xrange functions in Python 2.X?
Python3
for loop with range function
To understand what for i in range() means in Python3, we need first to understand the working of the range() function.
The range() function uses the generator to produce numbers. It doesn’t generate all numbers at once.
As you know range() returns the range object. A range object uses the same (small) amount of memory, no matter the size of the range it represents. It only stores the start, stop and step values and calculates individual items and subranges as needed.
I.e., It generates the next value only when for loop iteration asked for it. In each loop iteration, It generates the next value and assigns it to the iterator variable i.
So it means range() produces numbers one by one as the loop moves to the next iteration. It saves lots of memory, which makes range() faster and efficient.
Reference: PyNative - for loop with range()

Python lists - codes & algorithem

I need some help with python, a new program language to me.
So, lets say that I have this list:
list= [3, 1, 4, 9, 8, 2]
And I would like to sort it, but without using the built-in function "sort", otherwise where's all the fun and the studying in here? I want to code as simple and as basic as I can, even if it means to work a bit harder. Therefore, if you want to help me and to offer me some of ideas and code, please, try to keep them very "basic".
Anyway, back to my problem: In order to sort this list, I've decided to compare every time a number from the list to the last number. First, I'll check 3 and 2. If 3 is smaller than 2 (and it's false, wrong), then do nothing.
Next - check if 1 is smaller than 2 (and it's true) - then change the index place of this number with the first element.
On the next run, it will check again if the number is smaller or not from the last number in the list. But this time, if the number is smaller, it will change the place with the second number (and on the third run with the third number, if it's smaller, of course).
and so on and so on.
In the end, the ()function will return the sorted list.
Hop you've understand it.
So I want to use a ()recursive function to make the task bit interesting, but still basic.
Therefore, I thought about this code:
def func(list):
if not list:
for i in range(len(list)):
if list[-1] > lst[i]:
#have no idea what to write here in order to change the locations
i = i + 1
#return func(lst[i+1:])?
return list
2 questions:
1. How can I change the locations? Using pop/remove and then insert?
2. I don't know where to put the recursive part and if I've wrote it good (I think I didn't). the recursive part is the second "#", the first "return".
What do you think? How can I improve this code? What's wrong?
Thanks a lot!
Oh man, sorting. That's one of the most popular problems in programming with many, many solutions that differ a little in every language. Anyway, the most straight-forward algorithm is I guess the bubble sort. However, it's not very effective, so it's mostly used for educational purposes. If you want to try something more efficient and common go for the quick sort. I believe it's the most popular sorting algorithm. In python however, the default algorithm is a bit different - read here. And like I've said, there are many, many more sorting algorithms around the web.
Now, to answer your specific questions: in python replacing an item in a list is as simple as
list[-1]=list[i]
or
tmp=list[-1]
list[-1]=list[i]
list[i]=tmp
As to recursion - I don't think it's a good idea to use it, a simple while/for loop is better here.
maybe you can try a quicksort this way :
def quicksort(array, up, down):
# start sorting in your array from down to up :
# is array[up] < array[down] ? if yes switch
# do it until up <= down
# call recursively quicksort
# with the array, middle, up
# with the array, down, middle
# where middle is the value found when the first sort ended
you can check this link : Quicksort on Wikipedia
It is nearly the same logic.
Hope it will help !
The easiest way to swap the two list elements is by using “parallel assignment”:
list[-1], list[i] = list[i], list[-1]
It doesn't really make sense to use recursion for this algorithm. If you call func(lst[i+1:]), that makes a copy of those elements of the list, and the recursive call operates on the copy, and then the copy is discarded. You could make func take two arguments: the list and i+1.
But your code is still broken. The not list test is incorrect, and the i = i + 1 is incorrect. What you are describing sounds a variation of selection sort where you're doing a bunch of extra swapping.
Here's how a selection sort normally works.
Find the smallest of all elements and swap it into index 0.
Find the smallest of all remaining elements (all indexes greater than 0) and swap it into index 1.
Find the smallest of all remaining elements (all indexes greater than 1) and swap it into index 2.
And so on.
To simplify, the algorithm is this: find the smallest of all remaining (unsorted) elements, and append it to the list of sorted elements. Repeat until there are no remaining unsorted elements.
We can write it in Python like this:
def func(elements):
for firstUnsortedIndex in range(len(elements)):
# elements[0:firstUnsortedIndex] are sorted
# elements[firstUnsortedIndex:] are not sorted
bestIndex = firstUnsortedIndex
for candidateIndex in range(bestIndex + 1, len(elements)):
if elements[candidateIndex] < elements[bestIndex]:
bestIndex = candidateIndex
# Now bestIndex is the index of the smallest unsorted element
elements[firstUnsortedIndex], elements[bestIndex] = elements[bestIndex], elements[firstUnsortedIndex]
# Now elements[0:firstUnsortedIndex+1] are sorted, so it's safe to increment firstUnsortedIndex
# Now all elements are sorted.
Test:
>>> testList = [3, 1, 4, 9, 8, 2]
>>> func(testList)
>>> testList
[1, 2, 3, 4, 8, 9]
If you really want to structure this so that recursion makes sense, here's how. Find the smallest element of the list. Then call func recursively, passing all the remaining elements. (Thus each recursive call passes one less element, eventually passing zero elements.) Then prepend that smallest element onto the list returned by the recursive call. Here's the code:
def func(elements):
if len(elements) == 0:
return elements
bestIndex = 0
for candidateIndex in range(1, len(elements)):
if elements[candidateIndex] < elements[bestIndex]:
bestIndex = candidateIndex
return [elements[bestIndex]] + func(elements[0:bestIndex] + elements[bestIndex + 1:])

Most efficient way to cycle over Python sublists while making them grow (insert method)?

My problem is about managing insert/append methods within loops.
I have two lists of length N: the first one (let's call it s) indicates a subset to which, while the second one represents a quantity x that I want to evaluate. For sake of simplicity, let's say that every subset presents T elements.
cont = 0;
for i in range(NSUBSETS):
for j in range(T):
subcont = 0;
if (x[(i*T)+j] < 100):
s.insert(((i+1)*T)+cont, s[(i*T)+j+cont]);
x.insert(((i+1)*T)+cont, x[(i*T)+j+cont]);
subcont += 1;
cont += subcont;
While cycling over all the elements of the two lists, I'd like that, when a certain condition is fulfilled (e.g. x[i] < 100), a copy of that element is put at the end of the subset, and then going on with the loop till completing the analysis of all the original members of the subset. It would be important to maintain the "order", i.e. inserting the elements next to the last element of the subset it comes from.
I thought a way could have been to store within 2 counter variables the number of copies made within the subset and globally, respectively (see code): this way, I could shift the index of the element I was looking at according to that. I wonder whether there exists some simpler way to do that, maybe using some Python magic.
If the idea is to interpolate your extra copies into the lists without making a complete copy of the whole list, you can try this with a generator expression. As you loop through your lists, collect the matches you want to append. Yield each item as you process it, then yield each collected item too.
This is a simplified example with only one list, but hopefully it illustrates the idea. You would only get a copy if you do like i've done and expand the generator with a comprehension. If you just wanted to store or further analyze the processed list (eg, to write it to disk) you could never have it in memory at all.
def append_matches(input_list, start, end, predicate):
# where predicate is a filter function or lambda
for item in input_list[start:end]:
yield item
for item in filter(predicate, input_list[start:end]):
yield item
example = lambda p: p < 100
data = [1,2,3,101,102,103,4,5,6,104,105,106]
print [k for k in append_matches (data, 0, 6, example)]
print [k for k in append_matches (data, 5, 11, example)]
[1, 2, 3, 101, 102, 103, 1, 2, 3]
[103, 4, 5, 6, 104, 105, 4, 5, 6]
I'm guessing that your desire not to copy the lists is based on your C background - an assumption that it would be more expensive that way. In Python lists are not actually lists, inserts have O(n) time as they are more like vectors and so those insert operations are each copying the list.
Building a new copy with the extra elements would be more efficient than trying to update in-place. If you really want to go that way you would need to write a LinkedList class that held prev/next references so that your Python code really was a copy of the C approach.
The most Pythonic approach would not try to do an in-place update, as it is simpler to express what you want using values rather than references:
def expand(origLs) :
subsets = [ origLs[i*T:(i+1)*T] for i in range(NSUBSETS) ]
result = []
for s in subsets :
copies = [ e for e in s if e<100 ]
result += s + copies
return result
The main thing to keep in mind is that the underlying cost model for an interpreted garbage-collected language is very different to C. Not all copy operations actually cause data movement, and there are no guarantees that trying to reuse the same memory will be successful or more efficient. The only real answer is to try both techniques on your real problem and profile the results.
I'd be inclined to make a copy of your lists and then, while looping across the originals, as you come across a criteria to insert you insert into the copy at the place you need it to be at. You can then output the copied and updated lists.
I think to have found a simple solution.
I cycle from the last subset backwards, putting the copies at the end of each subset. This way, I avoid encountering the "new" elements and get rid of counters and similia.
for i in range(NSUBSETS-1, -1, -1):
for j in range(T-1, -1, -1):
if (x[(i*T)+j] < 100):
s.insert(((i+1)*T), s[(i*T)+j])
x.insert(((i+1)*T), x[(i*T)+j])
One possibility would be using numpy's advanced indexing to provide the illusion of copying elements to the ends of the subsets by building a list of "copy" indices for the original list, and adding that to an index/slice list that represents each subset. Then you'd combine all the index/slice lists at the end, and use the final index list to access all your items (I believe there's support for doing so generator-style, too, which you may find useful as advanced indexing/slicing returns a copy rather than a view). Depending on how many elements meet the criteria to be copied, this should be decently efficient as each subset will have its indices as a slice object, reducing the number of indices needed to keep track of.

Categories