Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
d36862cf
Commit
d36862cf
authored
Feb 21, 2007
by
Raymond Hettinger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add itertools.izip_longest().
parent
15cade05
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
317 additions
and
0 deletions
+317
-0
Doc/lib/libitertools.tex
Doc/lib/libitertools.tex
+27
-0
Lib/test/test_itertools.py
Lib/test/test_itertools.py
+54
-0
Misc/NEWS
Misc/NEWS
+2
-0
Modules/itertoolsmodule.c
Modules/itertoolsmodule.c
+234
-0
No files found.
Doc/lib/libitertools.tex
View file @
d36862cf
...
@@ -302,6 +302,33 @@ by functions or loops that truncate the stream.
...
@@ -302,6 +302,33 @@ by functions or loops that truncate the stream.
don't care about trailing, unmatched values from the longer iterables.
don't care about trailing, unmatched values from the longer iterables.
\end{funcdesc}
\end{funcdesc}
\begin{funcdesc}
{
izip
_
longest
}{
*iterables
\optional
{
, fillvalue
}}
Make an iterator that aggregates elements from each of the iterables.
If the iterables are of uneven length, missing values are filled-in
with
\var
{
fillvalue
}
. Iteration continues until the longest iterable
is exhausted. Equivalent to:
\begin{verbatim}
def izip
_
longest(*args, **kwds):
fillvalue = kwds.get('fillvalue')
def sentinel(counter = ([fillvalue]*(len(args)-1)).pop):
yield counter() # yields the fillvalue, or raises IndexError
fillers = repeat(fillvalue)
iters = [chain(it, sentinel(), fillers) for it in args]
try:
for tup in izip(*iters):
yield tup
except IndexError:
pass
\end{verbatim}
If one of the iterables is potentially infinite, then the
\function
{
izip
_
longest()
}
function should be wrapped with something
that limits the number of calls (for example
\function
{
islice()
}
or
\function
{
take()
}
).
\versionadded
{
2.6
}
\end{funcdesc}
\begin{funcdesc}
{
repeat
}{
object
\optional
{
, times
}}
\begin{funcdesc}
{
repeat
}{
object
\optional
{
, times
}}
Make an iterator that returns
\var
{
object
}
over and over again.
Make an iterator that returns
\var
{
object
}
over and over again.
Runs indefinitely unless the
\var
{
times
}
argument is specified.
Runs indefinitely unless the
\var
{
times
}
argument is specified.
...
...
Lib/test/test_itertools.py
View file @
d36862cf
...
@@ -198,6 +198,51 @@ class TestBasicOps(unittest.TestCase):
...
@@ -198,6 +198,51 @@ class TestBasicOps(unittest.TestCase):
ids
=
map
(
id
,
list
(
izip
(
'abc'
,
'def'
)))
ids
=
map
(
id
,
list
(
izip
(
'abc'
,
'def'
)))
self
.
assertEqual
(
len
(
dict
.
fromkeys
(
ids
)),
len
(
ids
))
self
.
assertEqual
(
len
(
dict
.
fromkeys
(
ids
)),
len
(
ids
))
def
test_iziplongest
(
self
):
for
args
in
[
[
'abc'
,
range
(
6
)],
[
range
(
6
),
'abc'
],
[
range
(
1000
),
range
(
2000
,
2100
),
range
(
3000
,
3050
)],
[
range
(
1000
),
range
(
0
),
range
(
3000
,
3050
),
range
(
1200
),
range
(
1500
)],
[
range
(
1000
),
range
(
0
),
range
(
3000
,
3050
),
range
(
1200
),
range
(
1500
),
range
(
0
)],
]:
target
=
map
(
None
,
*
args
)
self
.
assertEqual
(
list
(
izip_longest
(
*
args
)),
target
)
self
.
assertEqual
(
list
(
izip_longest
(
*
args
,
**
{})),
target
)
target
=
[
tuple
((
e
is
None
and
'X'
or
e
)
for
e
in
t
)
for
t
in
target
]
# Replace None fills with 'X'
self
.
assertEqual
(
list
(
izip_longest
(
*
args
,
**
dict
(
fillvalue
=
'X'
))),
target
)
self
.
assertEqual
(
take
(
3
,
izip_longest
(
'abcdef'
,
count
())),
zip
(
'abcdef'
,
range
(
3
)))
# take 3 from infinite input
self
.
assertEqual
(
list
(
izip_longest
()),
zip
())
self
.
assertEqual
(
list
(
izip_longest
([])),
zip
([]))
self
.
assertEqual
(
list
(
izip_longest
(
'abcdef'
)),
zip
(
'abcdef'
))
self
.
assertEqual
(
list
(
izip_longest
(
'abc'
,
'defg'
,
**
{})),
map
(
None
,
'abc'
,
'defg'
))
# empty keyword dict
self
.
assertRaises
(
TypeError
,
izip_longest
,
3
)
self
.
assertRaises
(
TypeError
,
izip_longest
,
range
(
3
),
3
)
for
stmt
in
[
"izip_longest('abc', fv=1)"
,
"izip_longest('abc', fillvalue=1, bogus_keyword=None)"
,
]:
try
:
eval
(
stmt
,
globals
(),
locals
())
except
TypeError
:
pass
else
:
self
.
fail
(
'Did not raise Type in: '
+
stmt
)
# Check tuple re-use (implementation detail)
self
.
assertEqual
([
tuple
(
list
(
pair
))
for
pair
in
izip_longest
(
'abc'
,
'def'
)],
zip
(
'abc'
,
'def'
))
self
.
assertEqual
([
pair
for
pair
in
izip_longest
(
'abc'
,
'def'
)],
zip
(
'abc'
,
'def'
))
ids
=
map
(
id
,
izip_longest
(
'abc'
,
'def'
))
self
.
assertEqual
(
min
(
ids
),
max
(
ids
))
ids
=
map
(
id
,
list
(
izip_longest
(
'abc'
,
'def'
)))
self
.
assertEqual
(
len
(
dict
.
fromkeys
(
ids
)),
len
(
ids
))
def
test_repeat
(
self
):
def
test_repeat
(
self
):
self
.
assertEqual
(
zip
(
xrange
(
3
),
repeat
(
'a'
)),
self
.
assertEqual
(
zip
(
xrange
(
3
),
repeat
(
'a'
)),
[(
0
,
'a'
),
(
1
,
'a'
),
(
2
,
'a'
)])
[(
0
,
'a'
),
(
1
,
'a'
),
(
2
,
'a'
)])
...
@@ -611,6 +656,15 @@ class TestVariousIteratorArgs(unittest.TestCase):
...
@@ -611,6 +656,15 @@ class TestVariousIteratorArgs(unittest.TestCase):
self
.
assertRaises
(
TypeError
,
list
,
izip
(
N
(
s
)))
self
.
assertRaises
(
TypeError
,
list
,
izip
(
N
(
s
)))
self
.
assertRaises
(
ZeroDivisionError
,
list
,
izip
(
E
(
s
)))
self
.
assertRaises
(
ZeroDivisionError
,
list
,
izip
(
E
(
s
)))
def
test_iziplongest
(
self
):
for
s
in
(
"123"
,
""
,
range
(
1000
),
(
'do'
,
1.2
),
xrange
(
2000
,
2200
,
5
)):
for
g
in
(
G
,
I
,
Ig
,
S
,
L
,
R
):
self
.
assertEqual
(
list
(
izip_longest
(
g
(
s
))),
zip
(
g
(
s
)))
self
.
assertEqual
(
list
(
izip_longest
(
g
(
s
),
g
(
s
))),
zip
(
g
(
s
),
g
(
s
)))
self
.
assertRaises
(
TypeError
,
izip_longest
,
X
(
s
))
self
.
assertRaises
(
TypeError
,
list
,
izip_longest
(
N
(
s
)))
self
.
assertRaises
(
ZeroDivisionError
,
list
,
izip_longest
(
E
(
s
)))
def
test_imap
(
self
):
def
test_imap
(
self
):
for
s
in
(
range
(
10
),
range
(
0
),
range
(
100
),
(
7
,
11
),
xrange
(
20
,
50
,
5
)):
for
s
in
(
range
(
10
),
range
(
0
),
range
(
100
),
(
7
,
11
),
xrange
(
20
,
50
,
5
)):
for
g
in
(
G
,
I
,
Ig
,
S
,
L
,
R
):
for
g
in
(
G
,
I
,
Ig
,
S
,
L
,
R
):
...
...
Misc/NEWS
View file @
d36862cf
...
@@ -127,6 +127,8 @@ Library
...
@@ -127,6 +127,8 @@ Library
- Added heapq.merge() for merging sorted input streams.
- Added heapq.merge() for merging sorted input streams.
- Added itertools.izip_longest().
- Have the encoding package'
s
search
function
dynamically
import
using
absolute
- Have the encoding package'
s
search
function
dynamically
import
using
absolute
import
semantics
.
import
semantics
.
...
...
Modules/itertoolsmodule.c
View file @
d36862cf
...
@@ -2472,6 +2472,238 @@ static PyTypeObject repeat_type = {
...
@@ -2472,6 +2472,238 @@ static PyTypeObject repeat_type = {
PyObject_GC_Del
,
/* tp_free */
PyObject_GC_Del
,
/* tp_free */
};
};
/* iziplongest object ************************************************************/
#include "Python.h"
typedef
struct
{
PyObject_HEAD
Py_ssize_t
tuplesize
;
Py_ssize_t
numactive
;
PyObject
*
ittuple
;
/* tuple of iterators */
PyObject
*
result
;
PyObject
*
fillvalue
;
PyObject
*
filler
;
/* repeat(fillvalue) */
}
iziplongestobject
;
static
PyTypeObject
iziplongest_type
;
static
PyObject
*
izip_longest_new
(
PyTypeObject
*
type
,
PyObject
*
args
,
PyObject
*
kwds
)
{
iziplongestobject
*
lz
;
Py_ssize_t
i
;
PyObject
*
ittuple
;
/* tuple of iterators */
PyObject
*
result
;
PyObject
*
fillvalue
=
Py_None
;
PyObject
*
filler
;
Py_ssize_t
tuplesize
=
PySequence_Length
(
args
);
if
(
kwds
!=
NULL
&&
PyDict_CheckExact
(
kwds
)
&&
PyDict_Size
(
kwds
)
>
0
)
{
fillvalue
=
PyDict_GetItemString
(
kwds
,
"fillvalue"
);
if
(
fillvalue
==
NULL
||
PyDict_Size
(
kwds
)
>
1
)
{
PyErr_SetString
(
PyExc_TypeError
,
"izip_longest() got an unexpected keyword argument"
);
return
NULL
;
}
}
/* args must be a tuple */
assert
(
PyTuple_Check
(
args
));
/* obtain iterators */
ittuple
=
PyTuple_New
(
tuplesize
);
if
(
ittuple
==
NULL
)
return
NULL
;
for
(
i
=
0
;
i
<
tuplesize
;
++
i
)
{
PyObject
*
item
=
PyTuple_GET_ITEM
(
args
,
i
);
PyObject
*
it
=
PyObject_GetIter
(
item
);
if
(
it
==
NULL
)
{
if
(
PyErr_ExceptionMatches
(
PyExc_TypeError
))
PyErr_Format
(
PyExc_TypeError
,
"izip_longest argument #%zd must support iteration"
,
i
+
1
);
Py_DECREF
(
ittuple
);
return
NULL
;
}
PyTuple_SET_ITEM
(
ittuple
,
i
,
it
);
}
filler
=
PyObject_CallFunctionObjArgs
((
PyObject
*
)(
&
repeat_type
),
fillvalue
,
NULL
);
if
(
filler
==
NULL
)
{
Py_DECREF
(
ittuple
);
return
NULL
;
}
/* create a result holder */
result
=
PyTuple_New
(
tuplesize
);
if
(
result
==
NULL
)
{
Py_DECREF
(
ittuple
);
Py_DECREF
(
filler
);
return
NULL
;
}
for
(
i
=
0
;
i
<
tuplesize
;
i
++
)
{
Py_INCREF
(
Py_None
);
PyTuple_SET_ITEM
(
result
,
i
,
Py_None
);
}
/* create iziplongestobject structure */
lz
=
(
iziplongestobject
*
)
type
->
tp_alloc
(
type
,
0
);
if
(
lz
==
NULL
)
{
Py_DECREF
(
ittuple
);
Py_DECREF
(
filler
);
Py_DECREF
(
result
);
return
NULL
;
}
lz
->
ittuple
=
ittuple
;
lz
->
tuplesize
=
tuplesize
;
lz
->
numactive
=
tuplesize
;
lz
->
result
=
result
;
Py_INCREF
(
fillvalue
);
lz
->
fillvalue
=
fillvalue
;
Py_INCREF
(
filler
);
lz
->
filler
=
filler
;
/* XXX */
return
(
PyObject
*
)
lz
;
}
static
void
izip_longest_dealloc
(
iziplongestobject
*
lz
)
{
PyObject_GC_UnTrack
(
lz
);
Py_XDECREF
(
lz
->
ittuple
);
Py_XDECREF
(
lz
->
result
);
Py_XDECREF
(
lz
->
fillvalue
);
Py_XDECREF
(
lz
->
filler
);
lz
->
ob_type
->
tp_free
(
lz
);
}
static
int
izip_longest_traverse
(
iziplongestobject
*
lz
,
visitproc
visit
,
void
*
arg
)
{
Py_VISIT
(
lz
->
ittuple
);
Py_VISIT
(
lz
->
result
);
Py_VISIT
(
lz
->
fillvalue
);
Py_VISIT
(
lz
->
filler
);
return
0
;
}
static
PyObject
*
izip_longest_next
(
iziplongestobject
*
lz
)
{
Py_ssize_t
i
;
Py_ssize_t
tuplesize
=
lz
->
tuplesize
;
PyObject
*
result
=
lz
->
result
;
PyObject
*
it
;
PyObject
*
item
;
PyObject
*
olditem
;
if
(
tuplesize
==
0
)
return
NULL
;
if
(
result
->
ob_refcnt
==
1
)
{
Py_INCREF
(
result
);
for
(
i
=
0
;
i
<
tuplesize
;
i
++
)
{
it
=
PyTuple_GET_ITEM
(
lz
->
ittuple
,
i
);
assert
(
PyIter_Check
(
it
));
item
=
(
*
it
->
ob_type
->
tp_iternext
)(
it
);
if
(
item
==
NULL
)
{
if
(
lz
->
numactive
<=
1
)
{
Py_DECREF
(
result
);
return
NULL
;
}
else
{
Py_INCREF
(
lz
->
filler
);
PyTuple_SET_ITEM
(
lz
->
ittuple
,
i
,
lz
->
filler
);
Py_INCREF
(
lz
->
fillvalue
);
item
=
lz
->
fillvalue
;
Py_DECREF
(
it
);
lz
->
numactive
-=
1
;
}
}
olditem
=
PyTuple_GET_ITEM
(
result
,
i
);
PyTuple_SET_ITEM
(
result
,
i
,
item
);
Py_DECREF
(
olditem
);
}
}
else
{
result
=
PyTuple_New
(
tuplesize
);
if
(
result
==
NULL
)
return
NULL
;
for
(
i
=
0
;
i
<
tuplesize
;
i
++
)
{
it
=
PyTuple_GET_ITEM
(
lz
->
ittuple
,
i
);
assert
(
PyIter_Check
(
it
));
item
=
(
*
it
->
ob_type
->
tp_iternext
)(
it
);
if
(
item
==
NULL
)
{
if
(
lz
->
numactive
<=
1
)
{
Py_DECREF
(
result
);
return
NULL
;
}
else
{
Py_INCREF
(
lz
->
filler
);
PyTuple_SET_ITEM
(
lz
->
ittuple
,
i
,
lz
->
filler
);
Py_INCREF
(
lz
->
fillvalue
);
item
=
lz
->
fillvalue
;
Py_DECREF
(
it
);
lz
->
numactive
-=
1
;
}
}
PyTuple_SET_ITEM
(
result
,
i
,
item
);
}
}
return
result
;
}
PyDoc_STRVAR
(
izip_longest_doc
,
"izip_longest(iter1 [,iter2 [...]], [fillvalue=None]) --> izip_longest object
\n
\
\n
\
Return an izip_longest object whose .next() method returns a tuple where
\n
\
the i-th element comes from the i-th iterable argument. The .next()
\n
\
method continues until the longest iterable in the argument sequence
\n
\
is exhausted and then it raises StopIteration. When the shorter iterables
\n
\
are exhausted, the fillvalue is substituted in their place. The fillvalue
\n
\
defaults to None or can be specified by a keyword argument.
\n
\
"
);
static
PyTypeObject
iziplongest_type
=
{
PyObject_HEAD_INIT
(
NULL
)
0
,
/* ob_size */
"itertools.izip_longest"
,
/* tp_name */
sizeof
(
iziplongestobject
),
/* tp_basicsize */
0
,
/* tp_itemsize */
/* methods */
(
destructor
)
izip_longest_dealloc
,
/* tp_dealloc */
0
,
/* tp_print */
0
,
/* tp_getattr */
0
,
/* tp_setattr */
0
,
/* tp_compare */
0
,
/* tp_repr */
0
,
/* tp_as_number */
0
,
/* tp_as_sequence */
0
,
/* tp_as_mapping */
0
,
/* tp_hash */
0
,
/* tp_call */
0
,
/* tp_str */
PyObject_GenericGetAttr
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_HAVE_GC
|
Py_TPFLAGS_BASETYPE
,
/* tp_flags */
izip_longest_doc
,
/* tp_doc */
(
traverseproc
)
izip_longest_traverse
,
/* tp_traverse */
0
,
/* tp_clear */
0
,
/* tp_richcompare */
0
,
/* tp_weaklistoffset */
PyObject_SelfIter
,
/* tp_iter */
(
iternextfunc
)
izip_longest_next
,
/* tp_iternext */
0
,
/* tp_methods */
0
,
/* tp_members */
0
,
/* tp_getset */
0
,
/* tp_base */
0
,
/* tp_dict */
0
,
/* tp_descr_get */
0
,
/* tp_descr_set */
0
,
/* tp_dictoffset */
0
,
/* tp_init */
0
,
/* tp_alloc */
izip_longest_new
,
/* tp_new */
PyObject_GC_Del
,
/* tp_free */
};
/* module level code ********************************************************/
/* module level code ********************************************************/
...
@@ -2485,6 +2717,7 @@ repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times\n\
...
@@ -2485,6 +2717,7 @@ repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times\n\
\n
\
\n
\
Iterators terminating on the shortest input sequence:
\n
\
Iterators terminating on the shortest input sequence:
\n
\
izip(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ...
\n
\
izip(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ...
\n
\
izip_longest(p, q, ...) --> (p[0], q[0]), (p[1], q[1]), ...
\n
\
ifilter(pred, seq) --> elements of seq where pred(elem) is True
\n
\
ifilter(pred, seq) --> elements of seq where pred(elem) is True
\n
\
ifilterfalse(pred, seq) --> elements of seq where pred(elem) is False
\n
\
ifilterfalse(pred, seq) --> elements of seq where pred(elem) is False
\n
\
islice(seq, [start,] stop [, step]) --> elements from
\n
\
islice(seq, [start,] stop [, step]) --> elements from
\n
\
...
@@ -2522,6 +2755,7 @@ inititertools(void)
...
@@ -2522,6 +2755,7 @@ inititertools(void)
&
ifilterfalse_type
,
&
ifilterfalse_type
,
&
count_type
,
&
count_type
,
&
izip_type
,
&
izip_type
,
&
iziplongest_type
,
&
repeat_type
,
&
repeat_type
,
&
groupby_type
,
&
groupby_type
,
NULL
NULL
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment