How to sort words alphabetically from a String?

Processing has its own container which replaces Java’s HashMap<String, Integer> called IntDict: :closed_book:

It’s easier to use, got some extra methods, but it’s slightly slower though: :flushed:
IntDict hmYPos = new IntDict();

2 Likes

Thank you very much @GoToLoop, now I’ll know for the future that Processing has its own container. It looks easier than HashMap, but still it’s good to know the original Java container! :grinning:

2 Likes

Dear Chrisir,
I hope u r fine and safe?!
I work, at least, on this project you helped me with 9 months ago!
I wanted to arrange the words along circles and they will rotate too, but I encounter a problem.
The posY of my sorted words don’t behave as I wish! I’d like the words beginning with ‘A’ to be at the center and the words begining with ‘Z’ on the farest circle, but I don’t find the solution…
If you have a bit of time would please have a look and guide me please?!!
Thanks a lot in advance and take care.
Best,

@lolonulu

import java.util.Map;
PFont font;
String[]lines={  
  "folly folly for to", 
  "for to what is the word", 
  "folly from this all this, folly from all this", 
  "given folly given all this seeing folly seeing all this this", 
  "what is the word this this", 
  "this this here all this this here", 
  "folly given all this seeing", 
  "folly seeing all this this here for to", 
  "what is the word", 
  "see glimpse seem to glimpse, need to seem to glimpse", 
  "folly for to need to seem to glimpse", 
  "what what is the word", 
  "and where folly for to need to seem to glimpse what where, where", 
  "what is the word", 
  "there over there away over there", 
  "afar afar away over there, afaint afaint afar away over there what", 
  "what what is the word", 
  "seeing all this all this this, all this this here", 
  "folly for to see what", 
  "glimpse seem to glimpse need to seem to glimpse", 
  "afaint afar away over there what", 
  "folly for to need to seem to glimpse afaint afar away over there what", 
  "what what is the word", 
  "what is the word"
};
int typeSize;
int x=0;
int y=0;
float r = 50;
String joinedText;
float interY;
char currentChar;
float w;
//int posX = 0;
// Note the HashMap's "key" is a String and "value" is an Integer
HashMap<String, Integer> hmYPos = new HashMap<String, Integer>();

//********************************************************************************************************************************************************

void setup() {
  size(1200, 1200);
  font = createFont("helvetica", 10);
  textFont(font);
  float ts=10;
  textSize(ts);
  //textAlign(CENTER);
  joinedText=join(lines, " ");
  prepare();
}

//********************************************************************************************************************************************************

void draw() {
  background(0);
  translate (width/2, height/2-150);
  smooth();
  int posX = 0;
  int posY = 0;  
  float arcLength=0; 
  scale(0.20);
  int lineDist= 20;

  // loop over the lines 
  for (int j = 0; j < lines.length; j++) { 
    //Calculate the number of words per sentence making array with the words in that line
    String[]wordsInThatLine = split(lines[j], " "); 

    for (int j2 = 0; j2 < wordsInThatLine.length; j2++) { 
      arcLength+=15*j2;

      //*****************************Arranging each char into concentric circles**********************************
      int index= hmYPos.get(wordsInThatLine[j2]);
      if (index<0) continue;
      //println(index);
    

      if ( j<=lines.length) {
        r=120*(j+1);
      }  
      // loop over the words in that line 
      for (int j3 = 0; j3 < wordsInThatLine[j2].length(); j3++) {  
        String s=str(wordsInThatLine[j2].charAt(j3)); 
        currentChar= wordsInThatLine[j2].charAt(j3);
        w=textWidth(currentChar);
        arcLength+=w/2+10; 
        float theta = PI+arcLength/r;
          // using the global HashMap to get the y pos of the sorted word
      float sortY = hmYPos.get(wordsInThatLine[j2])*-1;
     
      // getting mouse pos 
      float m=map(mouseX, 0, width, -0.2, 1.2);
      m = constrain(m, 0, 1);
      interY = lerp(posY, sortY, m);

        pushMatrix();
        rotate(-PI/2);
        //rotate(frameCount*0.025);  
        translate(r*cos(theta), r*sin(theta));
        rotate(theta+PI/2);
        noFill();
        stroke(181, 157, 0, 250);
        strokeWeight(3);
        bezier(posX+30, posY-50, posX+40, posY+150, posX-120, interY+60, posX, interY);
        noFill();
        strokeWeight(hmYPos.get(wordsInThatLine[j2])*0.025);
        stroke(0, 50, 220, 100);
        ellipse(posX, interY-80, hmYPos.get(wordsInThatLine[j2])*0.15+2, hmYPos.get(wordsInThatLine[j2])*0.15+2);
        noStroke();
        fill(255);
        float SText = hmYPos.get(wordsInThatLine[j2])*0.15+10;
        textSize(SText+20);
        text(currentChar, posX, interY);
        popMatrix();
        
        arcLength +=w/2;
        if ( currentChar==' ') {
          arcLength+=40;
        }
      }
      //***********************************************************************************************************
    }
  }
}

//func 
//------------------------------------------------------------------------------------------------------------------------------------

void prepare() {
  HashMap<String, Integer> hm1 = new HashMap<String, Integer>();
  String allLinesAsString;
  String[] lines2; 
  String[] words={};
  String[] wordsList2;

  // Init hm1
  // we create a parallel list to wordsList : wordsList2
  wordsList2 = split(join(lines, " "), " "); 
  for (String s : wordsList2) {
    //Putting key(String)-value(Integer) pairs in the HashMap
    hm1.put(s.toLowerCase().trim(), 0); // all 0
  }
  // We group all the lines in a single String
  allLinesAsString = join(lines, " ");
  // We split the group again
  lines2=split(allLinesAsString, " ");

  // Counting (filling hm1)
  for (int i=0; i<lines2.length; i++) {
    String word = lines2[i].toLowerCase().trim();
    if (hm1.get(word) != null) {
      // here we fill hm1 if it's not equal to null
      hm1.put(word, ((int) (hm1.get(word)))+1);  // add 1
    }
  }

  //// Using an enhanced loop to iterate over each entry of hm1
  for (Map.Entry me : hm1.entrySet()) {
    // copy hm1 to words 
    words = (String[]) append (words, me.getKey());
  }//for

  words=sort(words);

  // simulate output and save the line number for each word in sorted position 
  int posY=20;

  for (String s : words) { 
    hmYPos.put( s, posY); 
    posY+=20;
  }
}//
1 Like

I hope you are safe too.

You changed my code, right?

I think posY from hmYPos.is a calue proportional to the word

Now use map to increase radius with posY and also increase angle from it (well can be multiple times 360 degree when you want a spiral)

then use the formula

x= cos(angle) * r + centerX
y= sin(angle) * r + centerY
1 Like

Laurent Mareschal
https://laurentmareschal.com

Hey Chrisir,
Thank you very much for your help.
I’m fine too, except people here in Paris don’t wear any mask nor gloves?!

When you tell use the formula:

x= cos(angle) * r + centerX
y= sin(angle) * r + centerY

you mean:

posX = cos(theta * angleFact) * r + width/2;
posY = sin(theta * angleFact) * r + height/2;

map to increase radius with posY ?
Like:
r=map(posY, height/2, height, 50, 50+120*(lines.length) ?!!
Sorry I managed somehow with a bit of trigonometry, but now I’m a bit lost!!
Thanks a lot.
Take care,
L

1 Like

Hello

sorry I overlooked this

This sounds correct!!

Dear Chrisir,
It only sounds correct… :unamused:
But I did this below. I simplified the code and tried to get radius and angle proportionnal to posY!
The 1rst line doesn’t move, don’t know how come?!
Thanks in advance for your help, as usual :wink:
Take care,
L

import java.util.Map;
PFont font;
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜß,.;:!? ";
String[]lines={  
  "folly folly for to", 
  "for to what is the word", 
  "folly from this all this, folly from all this", 
};
int typeSize;
int x=0;
int y=0;
float r = 100;
String joinedText;
float interY;
char currentChar;
float w;
//int posX = 0;
// Note the HashMap's "key" is a String and "value" is an Integer
HashMap<String, Integer> hmYPos = new HashMap<String, Integer>();

//********************************************************************************************************************************************************

void setup() {
  size(1000, 1000);
  font = createFont("helvetica", 10);
  textFont(font);
  float ts=10;
  textSize(ts);
  //textAlign(CENTER);
  joinedText=join(lines, " ");
  prepare();
}

//********************************************************************************************************************************************************

void draw() {
  background(0);
  translate (width/2, height/2);
  smooth();
  float posX = 0;
  float posY = 0;  
  float arcLength=0; 
  scale(0.20);
  int lineDist= 20;

  // loop over the lines 
  for (int j = 0; j < lines.length; j++) { 
    //Calculate the number of words per sentence making array with the words in that line
    String[]wordsInThatLine = split(lines[j], " "); 
    for (int j2 = 0; j2 < wordsInThatLine.length; j2++) { 
      arcLength+=20;

      //*****************************Arranging each char into concentric circles**********************************
      int index= hmYPos.get(wordsInThatLine[j2]);
      if (index<0) continue;
 
      if ( j<=lines.length) {
        r=map(posY, height/2, height, 30*j+30, 100+300*lines.length);
      }
      float sortY=0; 
      sortY = hmYPos.get(wordsInThatLine[j2])*j*2;
      // getting mouse pos 
      float m=map(mouseX, 0, width, 0, 1);
      m = constrain(m, 0, 1);
      interY = lerp(posY, sortY, m);
      // loop over the words in that line 

      for (int j3 = 0; j3 < wordsInThatLine[j2].length(); j3++) {  
        String s=str(wordsInThatLine[j2].charAt(j3)); 
        currentChar= wordsInThatLine[j2].charAt(j3);
        w=textWidth(currentChar);
        arcLength+=w/2+10; 
        float theta = PI+arcLength/r;
        theta += map(posY, height/2, height, TWO_PI, TWO_PI*lines.length);
        pushMatrix();
        rotate(-PI/2); 
        translate(r*cos(theta), r*sin(theta));
        rotate(theta+PI/2);
        noStroke();
        fill(255);
        float SText = hmYPos.get(wordsInThatLine[j2])*0.15+30;
        textSize(SText+20);
        text(currentChar, posX, interY);
        popMatrix();

        arcLength +=w/2;
        if ( currentChar==' ') {
          arcLength+=10;
        }
      }
      //***********************************************************************************************************
    }
  }
}


//func 

//------------------------------------------------------------

void prepare() {
  HashMap<String, Integer> hm1 = new HashMap<String, Integer>();
  String allLinesAsString;
  String[] lines2; 
  String[] words={};
  String[] wordsList2;

  // Init hm1
  // we create a parallel list to wordsList : wordsList2
  wordsList2 = split(join(lines, " "), " "); 
  for (String s : wordsList2) {
    //Putting key(String)-value(Integer) pairs in the HashMap
    hm1.put(s.toLowerCase().trim(), 0); // all 0
  }
  // We group all the lines in a single String
  allLinesAsString = join(lines, " ");
  // We split the group again
  lines2=split(allLinesAsString, " ");

  // Counting (occurences in hm1)
  for (int i=0; i<lines2.length; i++) {
    String word = lines2[i].toLowerCase().trim();
    if (hm1.get(word) != null) {
      // here we fill hm1 if it's not equal to null
      hm1.put(word, ((int) (hm1.get(word)))+1);  // add 1
    }
  }

  //// Using an enhanced loop to iterate over each entry of hm1
  for (Map.Entry me : hm1.entrySet()) {
    // copy hm1 to words 
    words = (String[]) append (words, me.getKey());
  }//for

  words=sort(words);

  // simulate output and save the line number for each word in sorted position 
  int posY=20;

  for (String s : words) { 
    hmYPos.put( s, posY); 
    posY+=20;
  }
}//

Hello,

Check out this topic:

I was able to modify my code example to generate this:

:)

2 Likes

Hi @glv,
Thank you very much for your message and your help. I tried your solution in a sketch apart, now I’ll
incoporate it into my sketch and will let you know if I managed ;))
It was one problem the 2nd is that the Strings (line 1) at the center of my composition don’t move
according to posY, maybe both will be solved, hopefully :partying_face:

Hello,

I was just sharing… you inspired me to try this.
There are many ways to do things and I just threw this together quickly.

Give consideration to text alignment.
I used in my example:
textAlign(CENTER, CENTER);

This may not be directly related but shows how text alignment can be a consideration:

Stay well!

:)

2 Likes

Hi @glv,
sorry for not replying earlier but I had a lot to do…
Thank you very much for sharing this code too! Cool!
In my attempt the letters are oriented, and also evenly distributed,
my problem stays the same, my posY coordinates!
My words are sorted according to the alphabet order and they move according to this index, but not
as it should since I pass world coordinates (y) and not polar coordinates… :sob:

Why are you passing world coordinates at all? Is it external data? Can you throw it away and just start from polar?

A hand-drawing of what you want your final output to look like might be helpful.

1 Like

Hey @jeremydouglass,

Thanks a lot for your reply and questions, I’ll make a drawing of my final output to show what id’ like to acheive!

Best,

Laurent

1 Like

Dear Jeremy,
Here is the final output I’d like to obtain…!


Now i manage to get the result but not the unsorted text of the beginning…!?
Thanks a lot for your hello
Take care,
L

Got it! And currently, what does your bad output look like? What is wrong with it?

1 Like

I was looking at your code posted from 9 days ago, just trying to understand what is working for you and what is not working for you.

Hey Jeremy,
I 've sold the problem* at last! (Instead of posY I needed to pass the polar coordinates according to radius). But I have a new one*: I wonder why my bezier curves don’t link between the same letters: A with A, B with B and so on?!
Should I create a letter class to pass each letter its coordinates ? letters[i].x, letters[i].y ?!
Thanks a lot four help.
Take care,
L

import java.util.Map;

PFont font;

String[]lines={  
  "folly folly for to for to", 
  "what is the word", 
  "folly from this all this folly from all this", 
  "given folly given all this seeing folly seeing all this this", 
  "what is the word", 
  "this this this this here all this this here folly given all this", 
  "seeing folly seeing all this this here for to", 
  "what is the word", 
  "see glimpse seem to glimpse need to seem to glimpse folly for to need to seem to glimpse what", 
  "what is the word", 
  "and where folly for to need to seem to glimpse what where where what is the word there over there away over there", 
  "afar afar away over there", 
  "afaint afaint afar away over there what what", 
  "what is the word", 
  "seeing all this all this this all this this here folly for to see what glimpse seem to glimpse need to seem to glimpse", 
  "afaint afar away over there what", 
  "folly for to need to seem to glimpse afaint afar away over there what", 
  "what", 
  "what is the word", 
  "what is the word"
};

// --------------------------------------------------------

String[] lines2; 
String[] c1={};
String[] wordsList2;
int Size;
float r = 40;
float angle = 0;


float interY; 
// Note the HashMap's "key" is a String and "value" is an Integer
HashMap<String, Integer> hmYPos = new HashMap<String, Integer>();

//********************************************************************************************************************************************************

void setup() {
  size(1400, 1400);
  font = createFont("helvetica", 20);
  textFont(font);
  textAlign(CENTER);
  prepare();
}

//********************************************************************************************************************************************************

void draw() {
  background(0);
  translate (width/2, height/2);
  smooth();
  scale(0.7);
  float posX = 0; 
  float arcLength=0;
  float posY = 0;
  for (int j = 0; j < lines.length; j++) {
    if ( j<=lines.length) {
      r=45*(j+1);
    }

    String[]wordsInThatLine = split(lines[j], " "); 
    for (int j2 = 0; j2 < wordsInThatLine.length; j2++) {
      int index = hmYPos.get(wordsInThatLine[j2]);

      if (index<0) continue;
      arcLength+=15;
      mouseX=constrain(mouseX, width/2, width);
      //float sortY = hmYPos.get(wordsInThatLine [j2]);
      float sortY = 0;
      r= map(mouseX, width/2, width, 75+45*j+1, 150+hmYPos.get(wordsInThatLine [j2])); 
      sortY=r;
      float m=map(mouseX, width/2, width, 0, 1);
      m = constrain(m, 0, 1);
      interY = lerp(posY, sortY, m);

      for (int j3 = 0; j3 < wordsInThatLine[j2].length(); j3++) {  
        char currentChar= wordsInThatLine[j2].charAt(j3);
        float w=textWidth(currentChar);
        arcLength+=w+5;
        float theta =PI+arcLength/r;
        
        pushMatrix();
        translate(r*cos(theta), r*sin(theta));
        scale(0.7);
        rotate(theta+PI/2); 
        noFill();
        stroke(181, 157, 0, 250);
        strokeWeight(1);
        bezier(posX, posY, currentChar, currentChar, currentChar,hmYPos.get(wordsInThatLine [j2]), posX, interY);
        //bezier(0, j3, 0,j2,j,hmYPos.get(wordsInThatLine[j2]),0, 0);
        noFill();
        strokeWeight(2);
        stroke(0, 50, 220, 200);
        ellipse(0, 0, 20, 20);
        fill(255, 200);
        textAlign(CENTER, BASELINE);
        float SText = hmYPos.get(wordsInThatLine[j2])*0.03;
        textSize(SText+20);
        text(currentChar, 0, 0);
        popMatrix();
        arcLength+=w/2;
      }
    }
  }
}

//------------------------------------------------------------

void prepare() {
  HashMap<String, Integer> hm1 = new HashMap<String, Integer>();
  String message;

  message= join(lines, " "); // Join all the separated strings
  lines2=split(message, ",");// Split them into sentences according to the comas
  // Now we have a copy of the whole text

  // Init 
  wordsList2 = split(join(lines, " "), " "); // We do the same than above for a new copy to initialize the HashMap
  for (String s : wordsList2) {              // We loop across the whole list of strings
    hm1.put(s.toLowerCase(), 0);             // We fill the HashMap (hm1) and put the strings to lowerCase and put all at 0
    textSize(abs(hm1.get(s)*5+Size)+15);     // We pass a textSize
  }

  // Counting 
  for (int i=0; i<lines2.length; i++) {           // We loop across the whole strings
    String word = lines2[i].toLowerCase().trim(); // We put the strings to lowerCase and get rid of comas, points, etc.
    if (hm1.get(word) != null) {                  // If the HashMap is not null
      hm1.put(word, ((int) (hm1.get(word)))+1);   // We fill the HashMap with the 2nd list of strings (word) and we add 1
    }
  }

  //// Using an enhanced loop to iterate over each entry
  for (Map.Entry me : hm1.entrySet()) {
    c1 = (String[]) append (c1, me.getKey());
  }//for
  c1=sort(c1); //We sort the strings according to the alphabet
  println(c1);

  // simulate output and save the line number for each word in sorted position 
  int posY=0;
  for (String s : c1) {
    hmYPos.put( s, posY); 
    //Size=hmYPos.get(s);
    posY += 25;
  }
}//
//

I see curves linking each letter to itself. So that is “A with A”. Which A with which A, specifically, do you want to link?

Are you meaning to call bezierVertex?

1 Like

Hi, Thanks a lot for your message!
Well, I’d like to link all the “A” letters in the text together and the all the “B” letters and so on… And not each letter to itself. Don’t think I need bezierVertex in this case!?
Thanks in advance.
Best,
L