Expand Comparison Chains

9

Unlike most languages, Python evaluates a<b<c as it would be done in mathematics, actually comparing the three numbers, as opposed to comparing the boolean a<b to c. The correct way to write this in C (and many others) would be a<b && b<c.

In this challenge, your task is to expand such comparison chains of arbitrary lengths from the Python/intuitive representation, to how it would be written in other languages.

Specifications

  • Your program will have to handle the operators: ==, !=, <, >, <=, >=.
  • The input will have comparison chains using only integers.
  • Don't worry about the trueness of any of the comparisons along the way, this is purely a parsing/syntactical challenge.
  • The input won't have any whitespace to prevent answers that trivialize parsing by splitting on spaces.
  • However, your output may have a single space surrounding either just the &&'s, or both the comparison operators and the &&'s, or neither, but be consistent.

Test Cases

Input                  Output
---------------------------------------------------------------

3<4<5                  3<4 && 4<5
3<4<5<6<7<8<9          3<4 && 4<5 && 5<6 && 6<7 && 7<8 && 8<9
3<5==6<19              3<5 && 5==6 && 6<19
10>=5<7!=20            10>=5 && 5<7 && 7!=20
15==15==15==15==15     15==15 && 15==15 && 15==15 && 15==15

This is , so shortest code in bytes wins!

Maltysen

Posted 2017-10-09T03:50:37.707

Reputation: 25 023

related – Maltysen – 2017-10-09T03:50:57.693

Can I have two spaces either side of the &&? – H.PWiz – 2017-10-09T04:34:40.360

@H.PWiz nope, srry. – Maltysen – 2017-10-09T04:35:28.047

Answers

6

Retina, 33 22 17 bytes

-5 bytes thanks to @MartinEnder

-2`\D(\d+)
$&&&$1

Try it online!

ovs

Posted 2017-10-09T03:50:37.707

Reputation: 21 408

@MartinEnder A pity 1>-2 doesn't work to limit from both ends at once... – Neil – 2017-10-09T07:57:07.923

@Neil yeah, Retina 1.0 will get a new limit syntax where that's possible. – Martin Ender – 2017-10-09T07:57:54.780

Could you post an explanation? – James – 2017-10-09T19:17:38.407

5

Husk, 16 14 bytes

Prints a space around each operator.

wJ"&&"m←C2X3ġ±

Try it online!

Explanation:

                  Implicit input, e.g            "3<4<5<6"
            ġ±    Group digits                   ["3","<","4","<","5","<","6"]
          X3      Sublists of length 3           [["3","<","4"],["<","4","<"],["4","<","5"],["<","5","<"],["5","<","6"]]
        C2        Cut into lists of length 2     [[["3","<","4"],["<","4","<"]],[["4","<","5"],["<","5","<"]],[["5","<","6"]]]
      m←          Take the first element of each [["3","<","4"],["4","<","5"],["5","<","6"]]
 J"&&"            Join with "&&"                 ["3","<","4","&&","4","<","5","&&","5","<","6"]
w                 Print, separates by spaces

H.PWiz

Posted 2017-10-09T03:50:37.707

Reputation: 10 962

Nice one. You could use w instead of ; for a more direct approach to joining strings with spaces – Leo – 2017-10-09T04:53:56.187

Oh yes, how didn't I think of that? – H.PWiz – 2017-10-09T04:54:41.113

3

Retina, 42 47 22 bytes

Massively golfed thanks to Kevin Cruijssen

(\D(\d+))(?=\D)
$1&&$2

Try it online!

ATaco

Posted 2017-10-09T03:50:37.707

Reputation: 7 898

(==|!=|<=?|>=?) can be \D+ – ovs – 2017-10-09T06:37:57.657

Similarly (?<!^|\d) can be (?<=\D). Also the (?=\d+) is unnecessary, the operator will always be followed by an operand, at which point you can drop the + after the \D. There's also $& instead of $1$2, and then a further byte can be saved by capturing behind and looking ahead instead of capturing ahead and looking behind. – Neil – 2017-10-09T08:02:57.570

(\D(\d+))(?=\D) on line 1, and $1&&$2 on line two is enough (22 bytes). Try it here. – Kevin Cruijssen – 2017-10-09T14:28:21.527

2

V, 37 bytes

òͨ䫄0-9& ]«©¨ä«©¨„0-9& ]«©/±² ¦¦ ²³

Try it online!

Hexdump:

00000000: f2cd a8e4 ab84 302d 3926 205d aba9 a8e4  ......0-9& ]....
00000010: aba9 a884 302d 3926 205d aba9 2fb1 b220  ....0-9& ]../.. 
00000020: a6a6 20b2 b3                             .. ..

James

Posted 2017-10-09T03:50:37.707

Reputation: 54 537

2

Clojure, 88 bytes

Update: subs instead of clojure.string/join.

#(subs(apply str(for[p(partition 3 2(re-seq #"(?:\d+|[^\d]+)" %))](apply str" && "p)))4)

NikoNyrh

Posted 2017-10-09T03:50:37.707

Reputation: 2 361

2

J, 59 46 bytes

4(}.;)_2{.\3' && '&;\]</.~0+/\@,2~:/\e.&'!<=>'

Try it online!

How it used to work

                        (0 , }. ~:&(e.&'!<=>') }:)

We’re looking for operator boundaries. “Beheaded” and “curtailed” strings are turned into zeroes and ones where 0s are digits, then xored together. Prepend zero to match the length.

                   +/\                      </. ]     Split on boundaries. 
              ┌──┬──┬─┬─┬─┬──┬──┐
              │10│>=│5│<│7│!=│20│
              └──┴──┴─┴─┴─┴──┴──┘
         3' && '&;\          Add && to infixes of 3.
              ┌────┬──┬──┬──┐
              │ && │10│>=│5 │
              ├────┼──┼──┼──┤
              │ && │>=│5 │< │
              ├────┼──┼──┼──┤
              │ && │5 │< │7 │
              ├────┼──┼──┼──┤
              │ && │< │7 │!=│
              ├────┼──┼──┼──┤
              │ && │7 │!=│20│
              └────┴──┴──┴──┘
    _2{.\                    Take even numbered rows.
;}.,                         Concatenate after dropping the first box.

FrownyFrog

Posted 2017-10-09T03:50:37.707

Reputation: 3 112

1

Python 2, 60 59 58 57 bytes

lambda s:re.sub(r'(\D(\d+))(?=\D)',r'\1&&\2',s)
import re

Try it online!

TFeld

Posted 2017-10-09T03:50:37.707

Reputation: 19 246

re.sub(r'\D(\d+)(?=\D)',r'\g<0>&&\1',s) saves 1 byte. – Neil – 2017-10-09T07:59:46.240

@Neil Thanks :) – TFeld – 2017-10-09T08:07:19.217

1

Charcoal, 29 bytes

≔ ηFθ«¿›ι9«F›η!⁺&&η≔ωη»≔⁺ηιηι
≔ ηFθ«F∧›ι9›η!⁺&&η≔⎇›ι9ω⁺ηιηι

Two slightly different formulations of the same basic algorithm. The input string is iterated by character. As digits are found they are collected in a variable. When a boundary between a number and operator is found, an extra "&&" plus the variable is printed and the variable is cleared. The variable is initially initialised to a space so that the first boundary doesn't trigger the extra "&&".

Neil

Posted 2017-10-09T03:50:37.707

Reputation: 95 035

1

Jelly, 16 bytes

e€ØDŒg⁸ṁṡ3m2j⁾&&

Try it online!

Explanation:

e€ØDŒg⁸ṁṡ3m2j⁾&& Uses Jelly stringification, thus full program only
eۯD             For each each char, 1 if it's in '0123456789', otherwise 0
    Œg           Split into longest runs of equal elements
      ⁸ṁ         Reshape original input like the list we just made
                 Reshaping will separate numbers from operators
        ṡ3       Get contiguous sublists of length 3
          m2     Keep every second item, starting from the first
                 This will keep every (number operator number) and
                 remove every (operator number operator) substring
            j⁾&& Join with '&&'

Erik the Outgolfer

Posted 2017-10-09T03:50:37.707

Reputation: 38 134

1

Java 8, 46 bytes

s->s.replaceAll("(\\D(\\d+))(?=\\D)","$1&&$2")

Explanation:

Try it here.

s->                       // Method with String as both parameter and return-type
   s.replaceAll("(\\D(\\d+))(?=\\D)",
                "$1&&$2") //  Replace the match of the regex
                          //  with the second String
                          // End of method (implicit / single-line return-statement)

Regex explanation:

(\D(\d+))(?=\D)   # 1) For all matches of this regex
   (\d+)          #  Capture group 2: a number (one or more digits)
(\D \d+ )         #  Capture group 1: anything but a number + the number
                  #   (`\D` will match the `=`, `!`, `<`, or `>`)
         (?=\D)   #  Look-ahead so everything after the match remains as is

 $1&&$2           # 2) Replace it with
 $1               #  Result of capture group 1 (trailing part of the equation + the number)
   &&             #  Literal "&&"
     $2           #  Result of capture group 2 (the number)

Step by step example of the replacements:

Initial:                             10>=5<7!=20
 Match of first replacement:            =5
 Replace with:                          =5&&5
After first replacement:             10>=5&&5<7!=20
 Match of second replacement:                <7
 Replace with:                               <7&&7
After second replacement (result):   10>=5&&5<7&&7!=20

Kevin Cruijssen

Posted 2017-10-09T03:50:37.707

Reputation: 67 575

0

Perl 5, 47 + 1 (-p) = 48 bytes

$\.=$1." && "x(!!$')while s/(\d+\D+(\d+))/$2/}{

Try it online!

Xcali

Posted 2017-10-09T03:50:37.707

Reputation: 7 671

0

Ruby, 37 bytes

->s{s.gsub(/\D(\d+)(?=\D)/,'\&&&\1')}

Try it online!

G B

Posted 2017-10-09T03:50:37.707

Reputation: 11 099

0

JavaScript (SpiderMonkey), 43 bytes

f=s=>s.replace(/(\W+(\d+))(?!$)/g,"$1&&$2")

Try it online!

Ephellon Dantzler

Posted 2017-10-09T03:50:37.707

Reputation: 103