@@ -778,3 +778,58 @@ def __enter__(self):
778
778
def __exit__ (self , type_ , value , traceback ):
779
779
if self .close_store :
780
780
self .store .close ()
781
+
782
+
783
+ class SequenceZip (object ):
784
+ """
785
+ Represents the "combination" of several sequences.
786
+
787
+ This is very similar to python's builtin zip but only accepts sequences and acts as a Sequence (it can be
788
+ indexed and has a len).
789
+
790
+ Parameters
791
+ ----------
792
+ sequences : Iterable of Sequence
793
+ Sequences to combine.
794
+
795
+ Examples
796
+ --------
797
+ >>> z = SequenceZip([['a', 'b', 'c'], [1, 2, 3]])
798
+ >>> for i in range(len(z)):
799
+ ... print(z[i])
800
+ ('a', 1)
801
+ ('b', 2)
802
+ ('c', 3)
803
+ >>> for v in z:
804
+ ... print(v)
805
+ ('a', 1)
806
+ ('b', 2)
807
+ ('c', 3)
808
+ >>> list(z[1:4])
809
+ [('b', 2), ('c', 3)]
810
+ """
811
+ def __init__ (self , sequences ):
812
+ self .sequences = sequences
813
+ length = len (sequences [0 ])
814
+ bad_length_seqs = [i for i , s in enumerate (sequences [1 :], start = 1 ) if len (s ) != length ]
815
+ if bad_length_seqs :
816
+ first_bad = bad_length_seqs [0 ]
817
+ raise ValueError ("sequence {} has a length of {} which is different from the length of the "
818
+ "first sequence ({})" .format (first_bad , len (sequences [first_bad ]), length ))
819
+ self ._length = length
820
+
821
+ def __len__ (self ):
822
+ return self ._length
823
+
824
+ def __getitem__ (self , key ):
825
+ if isinstance (key , (int , np .integer )):
826
+ return tuple (seq [key ] for seq in self .sequences )
827
+ else :
828
+ assert isinstance (key , slice ), "key (%s) has invalid type (%s)" % (key , type (key ))
829
+ return SequenceZip ([seq [key ] for seq in self .sequences ])
830
+
831
+ def __iter__ (self ):
832
+ return iter (zip (* self .sequences )) if PY2 else zip (* self .sequences )
833
+
834
+ def __repr__ (self ):
835
+ return 'SequenceZip({})' .format (self .sequences )
0 commit comments