views:

831

answers:

10

Hi, what is an easy/effective way to combine an array of words together with a space in between, but no space before or after?

I suppose it is possible to remove the space after combining everything in a loop (something like sum += (term + " "))...I don't like it though.

Preferably code in Java, Python, or Ruby.

Thanks!

+1  A: 

What you want is String.Join, but since just saying that probably won't help you, here are some Join implementations in Java. Here's a string utility that has a join for Java.

JP Alioto
A: 

Eric Lippert had a great post about this problem a few weeks back.

Jason
+12  A: 

Well, in Python it will be straightforward using join:

values = ["this", "is", "your", "array"]
result = " ".join(values)
Pablo Santa Cruz
You should generally avoid using 'str' as a variable name, because it is a built-in type.
John Fouhy
Yup. Thanks John for pointing that out and thanks Carl for editing it.
Pablo Santa Cruz
A: 

Let's not forget the good old-fashioned

 for s in strArray do
     print s
     print " "
Charlie Martin
He doesn't want a space at the end of the string though...
DeadHead
A: 

Well, I know Python has a function like this, and I'm assuming Ruby does, and Java.

The join function takes an array of strings (depending on the language, it can be other types) and joins them together with a character (or another string) that you choose.

Python code:

wordString = " ".join(["word", "another", "word"])

Otherwise, you can loop through, the array, adding the word and a space, and test if it is the last element. If it is, just add the word, and not the space.

Python code again: (thanks to PTBNL for the suggestion)

wordArray =  ["word", "another", "word"]
wordString = ""
for i in range(0, len(wordArray) - 1):
    wordString += wordArray[i] + " "
wordString += wordArray[len(wordArray) - 1]
DeadHead
thanks for the " ".join() but the second one works fine but not so elegant.
Devoted
Why loop through the whole array? Stop at the next to last element and then concatenate the last element outside the loop. I think this is no less elegant. Also, it will save processing time by eliminating the if check in each pass of the loop.
PTBNL
True... I'll edit.. even though its a tad late now.. eh.
DeadHead
I'd agree second version is not less elegant, IT'S AN ABSOLUTE FUCKING NIGHTMARE!
SilentGhost
I'm guessing you've never worked in a low level language before.If you're implementing this in a language that does not have join(), then there's not really another way to do it. Personally, I wouldn't call this a nightmare, and is perfectly readable to me, even had someone else written it.
DeadHead
Python is dynamically typed; you don't declare types with variables. So "string wordString = ..." is incorrect; it should just be "wordString = ...".
John Fouhy
@DeadHead: but Python *does* have join! that optimised to do joins, there's no need for these dirty tricks from parallel universe.
SilentGhost
True, but I was giving it as an alternative, if he ever uses a language later on which doesn't have join but needs it.
DeadHead
+7  A: 

Yes, this is what join was made for. Here is the Ruby version:

["word", "another", "word"].join(" ")

<flamebait> As you can see, Ruby makes join a method on Array instead of String, and is thus far more sensible. </flamebait>

Jesse Hallett
why that is more sensiblehaving join in string allows me to join any iterator, my own implemented one instead of adding join to each possible iterator
Anurag Uniyal
It's not more "sensible"; it just looks more "customary". In python, you're asking the space character to join the string elements of the iterable argument, which doesn't need to be a list.
ΤΖΩΤΖΙΟΥ
Yeah, you are both right. I just like to make jabs at Python sometimes :)Incidentally, in Ruby the `join` method is actually defined on a module called `Enumerable`. Any class can get array-like behavior - including a `join` method - by including `Enumerable`. In the standard library both `Array` and `Hash` include `Enumerable` in this way.So from a Ruby perspective, the Ruby way is very sensible.
Jesse Hallett
Yeah but then you get everything else that comes with the Enumerable class. If you only want the join method then wouldnt you be bloating your program by bringing in the entire class just for one method.
Matt
+1  A: 

Straight from one of my existing utilz classes

C:\java\home\src\krc\utilz\Arrayz.java

package krc.utilz;

/**
 * A bunch of static helper methods for arrays of String's.
 * @See also krc.utilz.IntArrays for arrays of int's.
 */
public abstract class Arrayz
{
  /**
   * Concetenates the values in the given array into a string, seperated by FS.
   * @param FS String - Field Seperator - Name borrowed from awk
   * @param Object[] a - array to be concatentated
   * @return a string representation of the given array.
   */
  public static String join(String FS, Object[] a) {
    if (a==null||a.length==0) return "";
    StringBuilder result = new StringBuilder(String.valueOf(a[0]));
    for(int i=1; i<a.length; i++) {
      result.append(FS);
      result.append(String.valueOf(a[i]));
    }
    return result.toString();
  }

  ....

}

Cheers. Keith.


EDIT

Here's a quick & dirty performance comparison, using java.util.Arrays as a baseline.

Note that hotspot cost is amortized over 100 iterations, and should be (more or less) the same for all three techniques... krc.utilz.RandomString and krc.utilz.Arrayz are both available upon request, just ask.

package forums;

import java.util.Arrays;
import krc.utilz.Arrayz;
import krc.utilz.RandomString;

class ArrayToStringPerformanceTest
{
  private static final int NS2MS = 1000000; // 1 millisecond (1/10^3) = 1,000,000 nanoseconds (1/10^9)

  public static void main(String[] args) {
    try {
      String[] array = randomStrings(100*1000, 16);
      long start, stop;
      String result;

      final int TIMES = 100;
      long time1=0L, time2=0L, time3=0L;

      for (int i=0; i<TIMES; i++) {

        start = System.nanoTime();
        result = Arrays.toString(array);
        stop = System.nanoTime();
        //System.out.println("Arrays.toString  took "+(stop-start)+" ns");
        time1 += (stop-start);

        start = System.nanoTime();
        result = Arrayz.join(", ", array);
        stop = System.nanoTime();
        //System.out.println("Arrayz.join      took "+(stop-start)+" ns");
        time2 += (stop-start);

        start = System.nanoTime();
        result = arrayToString(array, ", ");
        stop = System.nanoTime();
        //System.out.println("arrayToString    took "+(stop-start)+" ns");
        time3 += (stop-start);

      }
      System.out.format("java.util.Arrays.toString  took "+(time1/TIMES/NS2MS)+" ms");
      System.out.format("krc.utilz.Arrayz.join      took "+(time2/TIMES/NS2MS)+" ms");
      System.out.format("arrayToString              took "+(time3/TIMES/NS2MS)+" ms");

    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static String arrayToString(String[] array, String spacer) {
    StringBuffer result = new StringBuffer();
    for ( int i=0; i<array.length; i++ ) {
      result.append( array[i] + ((i+1<array.length)?spacer:"") );
    }
    return result.toString();
  }

  private static String[] randomStrings(int howMany, int length) {
    RandomString random = new RandomString();
    String[] a = new String[howMany];
    for ( int i=0; i<howMany; i++) {
      a[i] = random.nextString(length);
    }
    return a;
  }

}

/*
C:\Java\home\src\forums>"C:\Program Files\Java\jdk1.6.0_12\bin\java.exe" -Xms512m -Xmx1536m -enableassertions -cp C:\Java\home\classes forums.ArrayToStringPerformanceTest

java.util.Arrays.toString  took 26 ms
krc.utilz.Arrayz.join      took 32 ms
arrayToString              took 59 ms
*/

See also Doomspork's suggestion, and my comment thereon.

Cheers. Keith.

corlettk
+1  A: 

Java could be accomplished with something like this:

public static String arrayToString(String[] array, String spacer) {
 StringBuffer result = new StringBuffer();
 for(int i = 0 ; i < array.length ; i++) {
  result.append(array[i] + ((i + 1 < array.length) ? spacer : ""));
 }
 return result.toString();
}
Doomspork
A few niggles with the code: (1) Making "spacer" the first argument caters for varargs.(2) StringBuilder is a bit faster than StringBuffer because StringBuilder doesn't have any synchronization overhead (i.e. it's not thread-safe). (3) The code "a[i] + whatever" creates a new StringBuilder object (StringBuffer pre-1.5) everytime through that loop. More garbage means a slower application.(4) There is no need to evaluate "is this the last one" everytime through the loop. Do it once, before first OR after last.(5) See http://en.wikipedia.org/wiki/Schlemiel_the_painter%27s_AlgorithmKeith;-)
corlettk
Good feedback, though I haven't the slightest idea what a niggle is. :) I wasn't aware of the StringBuilder advantages, thanks for the heads up!
Doomspork
A: 

In Python, you ask the join string to join an iterable of strings:

alist= ["array", "of", "strings"]
output= " ".join(alist)

If this notation seems weird to you, you can do the same thing in a different syntax:

output= str.join(" ", alist)

This works for any iterable (lists, tuples, dictionaries, generators, generator expressions…), as long as the items are all strings (or unicode strings).

You can substitute unicode for str (or u' ' for ' ') if you want a unicode result.

ΤΖΩΤΖΙΟΥ
+1  A: 

This will work in Ruby as well:

['a', 'list', 'of', 'words'] * " "
Psynix