How to store two space-separated variables as one element in a list to output the element later as integer datatypes - python

I'd like to append two space-separated integer variables to a list as an element, then later output the contents of the list on newlines. For example,
storage = a + 3, b + 3
lst.append(storage)
Later, when printing the elements of the list, I get:
for i in lst:
print(i)
>>> (4, 7)
>>> (3, 6)
>>> (7, 7)
Instead, I'd like the output to be exactly:
>>> 4 7
>>> 3 6
>>> 7 7
separated on newlines as a space-separated pair of integers without commas and not part of a list. In addition, I also input singular integers between the pairs and would like to output them on a newline as well:
for i in lst:
print(i)
Expected output:
>>> 1
>>> 4 7
>>> 3 6
>>> -1
>>> 7 7
>>> 3
How can I do this without using list comprehension/mapping/defined functions/importing?

Test each element to see if it's a tuple, and if it is, use the * operator to spread it as multiple args to print().
>>> lst = [1, (4, 7), (3, 6), -1, (7, 7), 3]
>>> for i in lst:
... if isinstance(i, tuple):
... print(">>>", *i)
... else:
... print(">>>", i)
...
>>> 1
>>> 4 7
>>> 3 6
>>> -1
>>> 7 7
>>> 3

Related

Find size/internal structure of list in Python

If I have a list c like so:
a = [1,2,3,4]
c = [a,a]
What's the simplest way of finding that it's a list of length two where each element is a list of length 4? If I do len(c) I get 2 but it doesn't give any indication that those elements are lists or their size unless I explicitly do something like
print(type(c[0]))
print(len(c[0]))
print(len(c[1]))
I could do something like
import numpy as np
np.asarray(c).shape
which gives me (2,4), but that only works when the internal lists are of equal size. If instead, the list is like
a = [1,2,3,4]
b = [1,2]
d = [a,b]
then np.asarray(d).shape just gives me (2,). In this case, I could do something like
import pandas as pd
df = pd.DataFrame(d)
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2 entries, 0 to 1
Data columns (total 4 columns):
0 2 non-null int64
1 2 non-null int64
2 1 non-null float64
3 1 non-null float64
dtypes: float64(2), int64(2)
memory usage: 144.0 bytes
From this, I can tell that there are lists inside the original list, but I would like to be able to see this without using pandas. What's the best way to look at the internal structure of a list?
Depending on the output format you expect, you could write a recursive function that returns nested tuples of length and shape.
Code
def shape(lst):
length = len(lst)
shp = tuple(shape(sub) if isinstance(sub, list) else 0 for sub in lst)
if any(x != 0 for x in shp):
return length, shp
else:
return length
Examples
lst = [[1, 2, 3, 4], [1, 2, 3, 4]]
print(shape(lst)) # (2, (4, 4))
lst = [1, [1, 2]]
print(shape(lst)) # (2, (0, 2))
lst = [1, [1, [1]]]
print(shape(lst)) # (2, (0, (2, (0, 1))))
This way is returning the type of element of list, and the first item is the parent list info.
def check(item):
res = [(type(item), len(item))]
for i in item:
res.append((type(i), (len(i) if hasattr(i, '__len__') else None)))
return res
>>> a = [1,2,3,4]
>>> c = [a,a]
>>> check(c)
[(list, 2), (list, 4), (list, 4)]

Call two keys at a same time from a dictionary on a for-loop [duplicate]

This question already has answers here:
How can I iterate over overlapping (current, next) pairs of values from a list?
(12 answers)
Closed 2 years ago.
Given a list
l = [1, 7, 3, 5]
I want to iterate over all pairs of consecutive list items (1,7), (7,3), (3,5), i.e.
for i in xrange(len(l) - 1):
x = l[i]
y = l[i + 1]
# do something
I would like to do this in a more compact way, like
for x, y in someiterator(l): ...
Is there a way to do do this using builtin Python iterators? I'm sure the itertools module should have a solution, but I just can't figure it out.
Just use zip
>>> l = [1, 7, 3, 5]
>>> for first, second in zip(l, l[1:]):
... print first, second
...
1 7
7 3
3 5
If you use Python 2 (not suggested) you might consider using the izip function in itertools for very long lists where you don't want to create a new list.
import itertools
for first, second in itertools.izip(l, l[1:]):
...
Look at pairwise at itertools recipes: http://docs.python.org/2/library/itertools.html#recipes
Quoting from there:
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return izip(a, b)
A General Version
A general version, that yields tuples of any given positive natural size, may look like that:
def nwise(iterable, n=2):
iters = tee(iterable, n)
for i, it in enumerate(iters):
next(islice(it, i, i), None)
return izip(*iters)
I would create a generic grouper generator, like this
def grouper(input_list, n = 2):
for i in xrange(len(input_list) - (n - 1)):
yield input_list[i:i+n]
Sample run 1
for first, second in grouper([1, 7, 3, 5, 6, 8], 2):
print first, second
Output
1 7
7 3
3 5
5 6
6 8
Sample run 1
for first, second, third in grouper([1, 7, 3, 5, 6, 8], 3):
print first, second, third
Output
1 7 3
7 3 5
3 5 6
5 6 8
Generalizing sberry's approach to nwise with comprehension:
def nwise(lst, k=2):
return list(zip(*[lst[i:] for i in range(k)]))
Eg
nwise(list(range(10)),3)
[(0, 1, 2), (1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6,
7), (6, 7, 8), (7, 8, 9)]
A simple means to do this without unnecessary copying is a generator that stores the previous element.
def pairs(iterable):
"""Yield elements pairwise from iterable as (i0, i1), (i1, i2), ..."""
it = iter(iterable)
try:
prev = next(it)
except StopIteration:
return
for item in it:
yield prev, item
prev = item
Unlike index-based solutions, this works on any iterable, including those for which indexing is not supported (e.g. generator) or slow (e.g. collections.deque).
You could use a zip.
>>> list(zip(range(5), range(2, 6)))
[(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
Just like a zipper, it creates pairs. So, to to mix your two lists, you get:
>>> l = [1,7,3,5]
>>> list(zip(l[:-1], l[1:]))
[(1, 7), (7, 3), (3, 5)]
Then iterating goes like
for x, y in zip(l[:-1], l[1:]):
pass
If you wanted something inline but not terribly readable here's another solution that makes use of generators. I expect it's also not the best performance wise :-/
Convert list into generator with a tweak to end before the last item:
gen = (x for x in l[:-1])
Convert it into pairs:
[(gen.next(), x) for x in l[1:]]
That's all you need.

How to exclude one min and one max number?

I have list:
numbers = [2,3,1,6,5]
And I must remove one min and one max number:
sorted(numbers)[1:-1]
And this is ok, but I want get additional information - position of removed numbers in original list:
remains = sorted(numbers)[1:-1]
min_number_position = 2
max_number_position = 3
How to do it? Numbers can be repeated.
Just use min and max functions in couple with index method of list to get position:
min_position = numbers.index(min(numbers))
max_position = numbers.index(max(numbers))
del numbers[min_position]
del numbers[max_position]
A pure python solution by creating arg sorted array (as created by numpy.argsort()) . Example -
numbers = [2,3,1,6,5]
argsorted = sorted(range(len(numbers)),key=lambda x:numbers[x])
maxpos,minpos = argsorted[-1],argsorted[0]
remains = [numbers[i] for i in argsorted[1:-1]]
Demo -
>>> numbers = [2,3,1,6,5]
>>> argsorted = sorted(range(len(numbers)),key=lambda x:numbers[x])
>>> argsorted
[2, 0, 1, 4, 3]
>>> maxpos,minpos = argsorted[-1],argsorted[0]
>>> remains = [numbers[i] for i in argsorted[1:-1]]
>>> remains
[2, 3, 5]
>>> maxpos
3
>>> minpos
2
If you can use numpy library, this can be easily done using array.argsort() . Example -
nnumbers = np.array(numbers)
nnumargsort = nnumbers.argsort()
minpos,maxpos = nnumargsort[[0,-1]]
remains = nnumbers[nnumargsort[1:-1]]
Demo -
In [136]: numbers = [2,3,1,6,5]
In [137]: nnumbers = np.array(numbers)
In [138]: nnumargsort = nnumbers.argsort()
In [139]: minpos,maxpos = nnumargsort[[0,-1]]
In [140]: remains = nnumbers[nnumargsort[1:-1]]
In [141]: remains
Out[141]: array([2, 3, 5])
In [142]: maxpos
Out[142]: 3
In [143]: minpos
Out[143]: 2
>>> sorted(enumerate(numbers), key=operator.itemgetter(1))
[(2, 1), (0, 2), (1, 3), (4, 5), (3, 6)]
The rest is left as an exercise for the reader.
You can use a function and return the index of max and min with list.index method :
>>> def func(li):
... sorted_li=sorted(li)
... return (li.index(sorted_li[0]),sorted_li[1:-1],li.index(sorted_li[-1]))
...
>>> min_number_position,remains,max_number_position=func(numbers)
>>> min_number_position
2
>>> remains
[2, 3, 5]
>>> max_number_position
3
In python 3.X you can use unpacking assignment :
>>> def func(li):
... mi,*re,ma=sorted(li)
... return (li.index(mi),re,li.index(ma))

How to limit for loop to print first few element from list in terms of their value in python?

I would like to limit for loop to print first few element from list in terms of their value. For example, if i < 6 :
list = [1,2,3,4,5,6,7,8,9,10]
for i < 6 in list:
print(i)
Thanks in advance !
In [9]: L = [1,2,3,4,5,6,7,8,9,10]
In [10]: for i in L:
....: if i<6:
....: print(i)
....:
1
2
3
4
5
based on I would like to limit for loop to print first few element from list in terms of their value it seems the list is in order so you can use itertools.takewhile :
from itertools import takewhile
lst = [1,2,3,4,5,6,7,8,9,10] # don't use list
tke = takewhile(lambda x: x< 6, lst)
for t in tke:
print(t)
1
2
3
4
5
If you want a list use list(...).
print(list(takewhile(lambda x: x< 6, lst))) # good reason why we should not use list as a variable name
[1, 2, 3, 4, 5]

How to loop n items at a time but not stepping only 1 each time? python [duplicate]

This question already has answers here:
Rolling or sliding window iterator?
(29 answers)
Closed 8 years ago.
I have a generator, let's say:
x = iter([1,2,3,4,5,6])
And if i want to loop 3 items at a time but step only 1 each time, i want to get:
1 2 3
2 3 4
3 4 5
5 6
I have tried looping two at a time but it steps 2 each time:
x = iter([1,2,3,4,5,6])
x = list(x)
for i,j in zip(x[::2],x[1::2]):
print i,j
[out]:
1 2
3 4
5 6
I have tried looping n at a time but it also steps n:
from itertools import izip_longest
def grouper(n, iterable, fillvalue=None):
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
x = iter([1,2,3,4,5,6])
for i,j in grouper(3,x):
print i,j
print
[out]:
Traceback (most recent call last):
File "test.py", line 11, in <module>
for i,j in grouper(3,x):
ValueError: too many values to unpack
I have tried just access +n each time i loop:
x = iter([1,2,3,4,5,6])
x = list(x)
for i,j in enumerate(x):
print x[i], x[i+1], x[i+2]
[out]:
1 2 3
2 3 4
3 4 5
4 5 6
5 6
Traceback (most recent call last):
File "test.py", line 26, in <module>
print x[i], x[i+1], x[i+2]
IndexError: list index out of range
Question:
Can I not change the generator into a list before looping and accessing more than one value at a time but stepping only 1 each time?
Other than using the last solution i have, how to else achieve the desired iteration?
You can use tee, islice and izip_longest as a base, and adapt the "stop" condition, eg:
from itertools import tee, islice, izip_longest
data = [1, 2, 3, 4, 5, 6]
iters = [islice(it, n, None) for n, it in enumerate(tee(data, 3))]
res = list(izip_longest(*iters))
# [(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6), (5, 6, None), (6, None, None)]
An example stop condition might be:
from itertools import takewhile
res = list(takewhile(lambda L: None not in L, izip_longest(*iters)))
# [(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]

Categories

Resources