From c0b597c24a6d43420ce59ae98e378b6bfc28b073 Mon Sep 17 00:00:00 2001 From: Kaushal Modi Date: Mon, 4 Nov 2019 08:56:12 -0500 Subject: [PATCH] Make sequtils.zip backwards compatible with Nim 1.0.x --- lib/pure/collections/sequtils.nim | 93 ++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim index 864aa0dbc865..f71f13358314 100644 --- a/lib/pure/collections/sequtils.nim +++ b/lib/pure/collections/sequtils.nim @@ -202,33 +202,49 @@ proc deduplicate*[T](s: openArray[T], isSorted: bool = false): seq[T] = for itm in items(s): if not result.contains(itm): result.add(itm) -proc zip*[S, T](s1: openArray[S], s2: openArray[T]): seq[(S, T)] = - ## Returns a new sequence with a combination of the two input containers. - ## - ## The input containers can be of different types. - ## If one container is shorter, the remaining items in the longer container - ## are discarded. - ## - runnableExamples: - let - short = @[1, 2, 3] - long = @[6, 5, 4, 3, 2, 1] - words = @["one", "two", "three"] - letters = "abcd" - zip1 = zip(short, long) - zip2 = zip(short, words) - zip3: seq[tuple[num: int, letter: char]] = zip(long, letters) - assert zip1 == @[(1, 6), (2, 5), (3, 4)] - assert zip2 == @[(1, "one"), (2, "two"), (3, "three")] - assert zip3 == @[(6, 'a'), (5, 'b'), (4, 'c'), (3, 'd')] - assert zip1[2][0] == 3 - assert zip2[1][1] == "two" - assert zip3[0].letter == 'a' +template zipImpl(s1, s2, retType: untyped): untyped = + proc zip*[S, T](s1: openArray[S], s2: openArray[T]): retType = + ## Returns a new sequence with a combination of the two input containers. + ## + ## The input containers can be of different types. + ## If one container is shorter, the remaining items in the longer container + ## are discarded. + ## + ## **Note**: For Nim 1.0.x and older version, ``zip`` returned a seq of + ## named tuple with fields ``a`` and ``b``. For Nim versions 1.1.x and newer, + ## ``zip`` returns a seq of unnamed tuples. + runnableExamples: + let + short = @[1, 2, 3] + long = @[6, 5, 4, 3, 2, 1] + words = @["one", "two", "three"] + letters = "abcd" + zip1 = zip(short, long) + zip2 = zip(short, words) + assert zip1 == @[(1, 6), (2, 5), (3, 4)] + assert zip2 == @[(1, "one"), (2, "two"), (3, "three")] + assert zip1[2][0] == 3 + assert zip2[1][1] == "two" + when (NimMajor, NimMinor) <= (1, 0): + let + zip3 = zip(long, letters) + assert zip3 == @[(a: 6, b: 'a'), (5, 'b'), (4, 'c'), (3, 'd')] + assert zip3[0].b == 'a' + else: + let + zip3: seq[tuple[num: int, letter: char]] = zip(long, letters) + assert zip3 == @[(6, 'a'), (5, 'b'), (4, 'c'), (3, 'd')] + assert zip3[0].letter == 'a' - var m = min(s1.len, s2.len) - newSeq(result, m) - for i in 0 ..< m: - result[i] = (s1[i], s2[i]) + var m = min(s1.len, s2.len) + newSeq(result, m) + for i in 0 ..< m: + result[i] = (s1[i], s2[i]) + +when (NimMajor, NimMinor) <= (1, 0): + zipImpl(s1, s2, seq[tuple[a: S, b: T]]) +else: + zipImpl(s1, s2, seq[(S, T)]) proc distribute*[T](s: seq[T], num: Positive, spread = true): seq[seq[T]] = ## Splits and distributes a sequence `s` into `num` sub-sequences. @@ -1067,20 +1083,29 @@ when isMainModule: zip1 = zip(short, long) zip2 = zip(short, words) zip3 = zip(ashort, along) - # As zip returns seq of anonymous tuples, they can be assigned - # to any variable that's a sequence of named tuples too. - zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords) - zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words) assert zip1 == @[(1, 6), (2, 5), (3, 4)] assert zip2 == @[(1, "one"), (2, "two"), (3, "three")] assert zip3 == @[(1, 6), (2, 5), (3, 4)] - assert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")] - assert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")] assert zip1[2][1] == 4 assert zip2[2][1] == "three" assert zip3[2][1] == 4 - assert zipXy[2].y == "three" - assert zipMn[2].n == "three" + when (NimMajor, NimMinor) <= (1, 0): + let + # In Nim 1.0.x and older, zip returned a seq of tuple strictly + # with fields named "a" and "b". + zipAb = zip(ashort, awords) + assert zipAb == @[(a: 1, b: "one"), (2, "two"), (3, "three")] + assert zipAb[2].b == "three" + else: + let + # As zip returns seq of anonymous tuples, they can be assigned + # to any variable that's a sequence of named tuples too. + zipXy: seq[tuple[x: int, y: string]] = zip(ashort, awords) + zipMn: seq[tuple[m: int, n: string]] = zip(ashort, words) + assert zipXy == @[(x: 1, y: "one"), (2, "two"), (3, "three")] + assert zipMn == @[(m: 1, n: "one"), (2, "two"), (3, "three")] + assert zipXy[2].y == "three" + assert zipMn[2].n == "three" block: # distribute tests let numbers = @[1, 2, 3, 4, 5, 6, 7]