Rosetta Challenge! -- Reverse a String

This is a Rosetta Challenge. Gratefully accepting answers for Processing, p5.js, processing.js, processing.py, p5py, JRubyArt, Processing.R, et cetera – including multiple approaches in one mode. Answers may be cross-posted to the linked Rosetta Code wiki and / or to Rosetta Examples.


Reverse a String

Task: Take a string and reverse it.
For example: “asdf” becomes “fdsa”.

Processing’s Java Mode:

// Discourse.Processing.org/t/rosetta-challenge-reverse-a-string/20644/2
// GoToLoop (2020/May/08)

static final String STR = "àéïõû";

void setup() {
  println(STR);
  println(reverseFast(STR));
  println(reverseSlow(STR));
  exit();
}

static final String reverseFast(final CharSequence s) {
  return new StringBuilder(s).reverse().toString();
}

static final String reverseSlow(final String s) {
  return new String(reverse(s.toCharArray()));
}

Java/Pjs Cross-Mode:

// Discourse.Processing.org/t/rosetta-challenge-reverse-a-string/20644/2
// GoToLoop (2020/May/08)

static final String[] TEXTS = { "asdf", "àéïõû" };

void setup() {
  println(TEXTS);
  println(reverseStr(TEXTS[0]) + " " + reverseStr(TEXTS[1]));
  exit();
}

static final String reverseStr(final String s) {
  return join(reverse(s.split("")), "");
}
1 Like

Processing’s Python Mode:

# Discourse.Processing.org/t/rosetta-challenge-reverse-a-string/20644/3
# GoToLoop (2020/May/08)

TEXTS = 'asdf', u'àéïõû'

def setup():
    print TEXTS[0], TEXTS[1]
    print reverseStr(TEXTS[0]), reverseStr(TEXTS[1])
    exit()


def reverseStr(s): return s[::-1]
2 Likes

Processing.R (R mode)

# ReverseAString in Processing.R
# Jeremy Douglass 2020-05-08 -- Processing 3.4 
# https://discourse.processing.org/t/rosetta-challenge-reverse-a-string/20644/2

setup <- function() {
  println(strrev("asdf"))
  println(strrev("àéïõû"))
  println(strrev("Lorem ipsum"))
}

strrev <- function(txt) {
  return(paste(rev(strsplit(txt, "")[[1]]), collapse = ""))
}

fdsa
ûõïéà
muspi meroL

2 Likes

p5.js:

// Discourse.Processing.org/t/rosetta-challenge-reverse-a-string/20644/5
// GoToLoop (2020/May/08)

const TEXTS = [ 'asdf', 'àéïõû' ];

function setup() {
  noCanvas();
  print(TEXTS);
  print(reverseStr(TEXTS[0]), reverseStr(TEXTS[1]));
}

function reverseStr(s) {
  return [...s].reverse().join('');
  //return s.split('').reverse().join('');
}
2 Likes

For me, this raises a question towards how to respond to tasks. With Flood Fill there are languages with a build-in function, but maybe answers should be low-leveled

String inputString = "àéïõû";
println(inputString);
String outString = "";
for (char c : inputString.toCharArray()) {
  outString = c + outString;
}
println(outString);
1 Like

I suppose another part of that is to present the answer in immediate mode (no setup, no draw).

So, in Processing.R, this is also a complete sketch:

println(paste(rev(strsplit("asdf", "")[[1]]), collapse = ""))

fdsa

1 Like

…and in p5py, the immediate mode sketch would be two lines:

from p5 import *
print("asdf"[::-1])

fdsa

Python Mode’s 1-liner: print u'àéïõû'[::-1]
Python 3’s 1-liner: print('àéïõû'[::-1])

1 Like

Yes. An example of what I mean is the task Draw a sphere. Should it be responded as it is, or like Phyton, right below it which takes a third of the page? What criteria should be prioritized?

Love this! Short and tasty implementation.

If one wants support for emojis (who doesn’t?! :blush:), split will fail, though, as it splits by UTF-16 code units (not Unicode characters). Array.from or ... (spread syntax) could be used instead:

const reverseStr = s => [...s].reverse().join('');
2 Likes

Included in the task, and it is driving me mad. Until now just frustration. Anyone!

Extra credit
Preserve Unicode combining characters.
For example, “as⃝df̅” becomes “f̅ds⃝a”, not “̅fd⃝sa”.

Is this measurable?
Slowest always fastest.

static final String STR = "àéïõû";
int start_time;

void setup() {
  println(STR);
  start_time = millis();
  for (int i = 0; i <= 100000000; i++) {
    String temp = reverseSlow(STR);
  }
  println(millis()-start_time);
   start_time = millis();
  for (int i = 0; i <= 100000000; i++) {
    String temp = reverseFast(STR);
  }
  println(millis()-start_time);
}


static final String reverseFast(final CharSequence s) {
  return new StringBuilder(s).reverse().toString();
}

static final String reverseSlow(final String s) {
  return new String(reverse(s.toCharArray()));
}
2 Likes

Nice catch @noel! :baseball:

I’ve just assumed a solution w/ StringBuilder would be faster, but I was wrong. :woozy_face:

Actually reverseSlow() is more than 2x faster than reverseFast()! :open_mouth:

However the Java/Pjs cross-mode reverseStr() is absurdly slower than the Java-only versions. :snail:

// Discourse.Processing.org/t/rosetta-challenge-reverse-a-string/20644/14
// GoToLoop (2020/May/09)

static final String STR = "àéïõû";
static final int ITERS = 10_000_000, LOOPS = 3, FUNCTS = 4;
final IntList timers = new IntList(LOOPS * FUNCTS);

void setup() {
  println("reverseStr(), reverseUnicode(), reverseSlow(), reverseFast()");

  for (int i = 0; i < LOOPS; ++i) {
    reverseStrMillis();
    reverseUnicodeMillis();
    reverseSlowMillis();
    reverseFastMillis();

    println(timers);
  }

  exit();
}

void reverseStrMillis() { // slowest
  final int start = millis();
  String s;

  for (int i = 0; i < ITERS; ++i)  s = reverseStr(STR);
  timers.append(millis() - start);
}

void reverseUnicodeMillis() { // slow
  final int start = millis();
  String s;

  for (int i = 0; i < ITERS; ++i)  s = reverseUnicode(STR);
  timers.append(millis() - start);
}

void reverseSlowMillis() { // fastest
  final int start = millis();
  String s;

  for (int i = 0; i < ITERS; ++i)  s = reverseSlow(STR);
  timers.append(millis() - start);
}

void reverseFastMillis() { // fast
  final int start = millis();
  String s;

  for (int i = 0; i < ITERS; ++i)  s = reverseFast(STR);
  timers.append(millis() - start);
}

static final String reverseStr(final String s) { // slowest
  return join(reverse(s.split("")), "");
}

static final String reverseUnicode(final CharSequence s) { // slow
  final int[] reversedUnicodes = reverse(s.codePoints().toArray());
  return new String(reversedUnicodes, 0, reversedUnicodes.length);
}

static final String reverseSlow(final String s) { // fastest
  return new String(reverse(s.toCharArray()));
}

static final String reverseFast(final CharSequence s) { // fast
  return new StringBuilder(s).reverse().toString();
}
2 Likes

I found it frustrating too. I believe that in order to correctly do this you need to correctly parse the unicode string into graphemes and reverse the grapheme list. Clearly there are implementations that are able to do this,

but I haven’t seen one for Java 8 – let alone a simple one. StringBuilder may have built-in support for this in some Java version… but given that PDE 3 can’t display these characters anyway – either in the editor or in output – I honestly don’t see the point of that part of the task for most Processing users.

How so?

ide screen

1 Like

Hmm. I may have launched 3.4 by habit.

So it looks like, in PDE 3.5.4,

as⃝df̅ … is the string
a sdf- … is what the editor can display, and
a sdf̅ … is what the window draws. So there is partial support.

In 3.4, the main difference is just the circle. The string in the editor separates the f and includes a broken-box image for the circle rather than silently dropping it, like this:

Screen Shot 2020-05-09 at 10.09.46 AM

and then draws with open boxes, like this:

Screen Shot 2020-05-09 at 10.09.25 AM

How about this 1 relying on CharSequence::codePoints()? :wink:
Docs.Oracle.com/en/java/javase/11/docs/api/java.base/java/lang/CharSequence.html#codePoints()

// Discourse.Processing.org/t/rosetta-challenge-reverse-a-string/20644/18
// GoToLoop (2020/May/09)

static final String TXT = "I💖🎮!";

void setup() {
  noLoop();

  background(#0000FF);
  fill(#FFFF00);
  textAlign(CENTER, BASELINE);

  println(TXT);
  text(TXT, width >> 1, height >> 2);

  final String rev = reverseUnicode(TXT);
  println(rev);
  text(rev, width >> 1, 3 * height >> 2);
}

static final String reverseUnicode(final CharSequence s) {
  final int[] reversedUnicodes = reverse(s.codePoints().toArray());
  return new String(reversedUnicodes, 0, reversedUnicodes.length);
}
1 Like

And apparently Python Mode doesn’t need any changes at all: :partying_face:

# Discourse.Processing.org/t/rosetta-challenge-reverse-a-string/20644/19
# GoToLoop (2020/May/09)

TEXTS = 'asdf', u'àéïõû', u'I💖🎮!'

def setup():
    print TEXTS
    print TEXTS[0], TEXTS[1], TEXTS[2]
    print reverseStr(TEXTS[0]), reverseStr(TEXTS[1]), reverseStr(TEXTS[2])
    exit()


def reverseStr(s): return s[::-1]

(‘asdf’, u’\xe0\xe9\xef\xf5\xfb’, u’I\U0001f496\U0001f3ae!’)

asdf àéïõû I💖🎮!

fdsa ûõïéà !:video_game::sparkling_heart:I

2 Likes

Very cool! but not quite yet. When I run that,
“as⃝df̅” incorrectly becomes “̅fd⃝sa” – with bar ahead of f, and circle on fd, not sa. That is the example of bad output that the wiki task gives.
It should output “f̅ds⃝a”.