25

So I have this "list" of ints. It could be a Vector, int[], List<Integer>, whatever.

My goal though is to sort the ints and end up with a String[]. How the int array starts out as is up in the air.

ex: Start with:{5,1,2,11,3} End with: String[] = {"1","2","3","5","11"}

Is there anyway to do this without a for loop? I have a for loop now for collecting the ints. I would rather skip doing another for loop.

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
dev4life
  • 880
  • 2
  • 8
  • 18
  • 2
    Please retag your question with the appropriate language. – Darin Dimitrov Sep 01 '10 at 15:48
  • 5
    Why do you want to avoid for loops? Any solution that anybody comes up with will have some sort of loop, even if it's hidden behind a method call. – Paul Tomblin Sep 01 '10 at 15:51
  • It says "This is for Java", it has a java tag, and it hasn't been edited - your comment seems pointless?!? I don't think it's possible to complete this without a loop (a few actually since sorting can only be done through some sort of loop/iterative process). – Rudu Sep 01 '10 at 15:52
  • 2
    @Rudi It may have been edited within 5 minutes of being posted, in which case the edit wouldn't show up. – ColinD Sep 01 '10 at 16:00
  • Maybe you should convert your int as Strings within your first loop. – Colin Hebert Sep 01 '10 at 16:02
  • @ColinD ah - fair enough :) It now reports it was edit 4 minutes later anyway *shrug* – Rudu Sep 01 '10 at 16:18
  • 1
    Seems to be two operations. How do I sort? [`Arrays.sort`/`Collections.sort`] How do I convert an `in[]`/`List` to a `String[]`? [see http://stackoverflow.com/questions/18524/java-best-way-of-converting-listinteger-to-liststring/61663#61663 ] – Tom Hawtin - tackline Sep 01 '10 at 16:57
  • It's a pity you're not using C#: `(new[] {5,1,2,11,3}).OrderBy(n => n).Select(n => n.ToString())` – StriplingWarrior Sep 01 '10 at 17:08
  • 3
    To treat your fear of multiple for loops, I would seek professional help. Start by reading Refactoring (Martin Fowler) and Working Effectively With Legacy Code (Michael Feathers)... – Javid Jamae Sep 01 '10 at 17:18

14 Answers14

22
int[] nums = {5,1,2,11,3}; //List or Vector
Arrays.sort(nums); //Collections.sort() for List,Vector
String a=Arrays.toString(nums); //toString the List or Vector
String ar[]=a.substring(1,a.length()-1).split(", ");
System.out.println(Arrays.toString(ar));

UPDATE:

A shorter version:

int[] nums = {-5,1,2,11,3};
Arrays.sort(nums);
String[] a=Arrays.toString(nums).split("[\\[\\]]")[1].split(", "); 
System.out.println(Arrays.toString(a));  
Emil
  • 13,577
  • 18
  • 69
  • 108
  • I think this could be the answer. I didn't want to interate through the list a second time because I'm already iterating to get the int list. Thank you. – dev4life Sep 07 '10 at 18:25
  • 1
    if your concerned about speed then its better to use the normal for loop once more because in Arrays.toString() they are using a for loop.Check the source(http://www.docjar.com/html/api/java/util/Arrays.java.html) But if you just want your code to look small then ok,you can use the above code or another option is just write small function to sent an int[] as input and return String[] array as output. – Emil Sep 07 '10 at 19:47
  • The "[\\[\\]]" is a regular expression, right? How did you know which one to use, and what exactly is it dictating? – Chance Sep 04 '14 at 21:37
  • The idea is to use `Arrays.toString` – FindOutIslamNow Aug 23 '18 at 13:18
14

Use a Stream which is available from Java 8. To get a Stream instance with "list" of ints:

  • For int[]
    • IntStream intStream = Arrays.Stream(nums); or
    • Stream<Integer> intStream = Arrays.Stream(nums).boxed(); if you need the same class as bottom one.
  • For any classes with Collection<Integer> interface (ex. Vector<Integer>, List<Integer>)
    • Stream<Integer> intStream = nums.stream();

Finally, to get a String[]:

String[] answer = intStream.sorted().mapToObj(String::valueOf).toArray(String[]::new);
Skywave
  • 193
  • 1
  • 7
8

Can I use a while loop instead?

@Test
public void test() {
    int[] nums = {5,1,2,11,3};

    Arrays.sort(nums);

    String[] stringNums = new String[nums.length];
    int i = 0;
    while (i < nums.length) {
        stringNums[i] = String.valueOf(nums[i++]);
    }

    Assert.assertArrayEquals(new String[]{"1","2","3","5","11"}, stringNums);
}

Using JUnit assertions.

Sorry, I'm being flippant. But saying you can't use a for loop is daft - you've got to iterate over the list somehow. If you're going to call a library method to sort it for you (cf Collections.sort()) - that will be looping somehow over the elements.

Noel M
  • 15,812
  • 8
  • 39
  • 47
5

Simple solution using Guava:

public List<String> toSortedStrings(List<Integer> ints) {
  Collections.sort(ints);
  return Lists.newArrayList(Iterables.transform(ints, 
      Functions.toStringFunction()));
}

Obviously, this solution (like any other) is going to use loops internally, but it gets it out of the code you have to read. You could also avoid changing the order in ints by passing the result of Ordering.natural().sortedCopy(ints) to transform instead of using Collections.sort first. Also, the Lists.newArrayList part is not necessary if you don't need to be able to add new elements to the resulting list.

The shortened version of that method body, with static imports:

return transform(Ordering.natural().sortedCopy(ints), toStringFunction());
ColinD
  • 108,630
  • 30
  • 201
  • 202
4

If you use a TreeSet, I have a (longish) one-liner for you (assuming items is the TreeSet):

final String[] arr =
    items.toString() // string representation
        .replaceAll("\\D+", " ") // replace all non digits with spaces
        .trim() // trim ends
        .split(" "); // split by spaces

Test code:

Set<Integer> items = new TreeSet<Integer>(Arrays.asList(5, 1, 2, 11, 3));

// insert above code here

System.out.println(Arrays.toString(arr));

Output:

[1, 2, 3, 5, 11]

EDIT:

OK, here is a different version that works with the int array directly. But unfortunately it's not a one-liner. However, it does keep duplicates and it's probably faster

EDIT again:

Bug fixed and negative numbers supported, as requested:

EDIT once more: only one regex pass and no trim

    final int[] in = { 5, 1, 2, 11, 3, 2, -5 }; // with duplicate
    Arrays.sort(in);
    final String[] out =
        Arrays.toString(in)
            .replaceAll("(?:\\[?)([-\\d]+)(?:\\]?)", "$1") // just remove [ and ]
            .split("\\s*,\\s*"); // split by comma

    System.out.println(Arrays.toString(out));

Output:

[-5, 1, 2, 2, 3, 5, 11]

Or completely without regex (apart from split()), but with one more step added:

final int[] in = { 5, 1, 2, 11, 3, 2, -5 }; // with duplicate
Arrays.sort(in);
final String stringRep = Arrays.toString(in);
final String[] out =
    stringRep.substring(1, stringRep.length() - 1).split("\\s*,\\s*");

System.out.println(Arrays.toString(out));

Output:

[-5, 1, 2, 2, 3, 5, 11]

Update: stripped whitespace from my last two solutions, hope you're happy now :-)

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
3

I would rather skip doing another for loop.

That's silly. It's a silly desire and a silly basis for undertaking a code exercise. If you can better express the qualities that you want your code to have, then we've got something to talk about - that it should be easy to read, say, or performant, or testable, or robust. But "I'd rather skip it" just doesn't give us anything useful to work with.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
3

Using Functional Java,

import fj.data.List;
import static fj.data.List.*;
import static fj.pre.Show.*;
.
.
.
final List<Integer> xs = list(5,1,2,11,3);
final List<String> ys = xs.sort(Ord.intOrd).map(
  new F<Integer, String>() {
    @Override public String f(final Integer i) {
       return String.valueOf(i);
    }
  }
);
listShow(stringShow).println(ys);
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
1

How about something like this:

List<String> stringList = new ArrayList<String>();
List<Integer> list = new ArrayList<Integer>(Arrays.asList(5,1,2,11,3));
Collections.sort(list);
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()) {
  stringList.add(iterator.next().toString());
}
System.out.println(stringList);
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
Adam
  • 43,763
  • 16
  • 104
  • 144
1

Using Eclipse Collections MutableIntList:

String[] result = IntLists.mutable.with(5, 1, 2, 11, 3)
        .sortThis()
        .collect(Integer::toString)
        .toArray(new String[]{});

Assert.assertArrayEquals(
        new String[]{"1", "2", "3", "5", "11"}, result);

Or trading some readability for potential efficiency:

MutableIntList intList = IntLists.mutable.with(5, 1, 2, 11, 3).sortThis();
String[] result = intList.injectIntoWithIndex(
        new String[intList.size()], 
        (r, each, index) -> {
            r[index] = Integer.toString(each);
            return r;
        });

Assert.assertArrayEquals(
        new String[]{"1", "2", "3", "5", "11"}, result);

Note: I am a committer for Eclipse Collections

Donald Raab
  • 6,458
  • 2
  • 36
  • 44
1

We can solve this problem using regular expression as follows:

int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8};
String str = new String(Arrays.toString(intArray));
String stripNoneDigits= str.replaceAll("[^\\d]", "");
String[] stringArray = stripNoneDigits.split("");
anothernode
  • 5,100
  • 13
  • 43
  • 62
Intelligent
  • 127
  • 1
  • 12
0

Why don't you simply cast those values to String within the original for loop, creating a String array rather than an int array? Assuming that you're gathering your initial integer from a starting point and adding to it on each for loop iteration, the following is a simple methodology to create a String array rather than an int array. If you need both int and String arrays with the same values in them, create them both in the same for loop and be done with it.

yourInt = someNumber;

for (int a = 0; a < aLimit; a ++) {

String stringName = String.valueOf(yourInt);
StringArrayName[a] = stringName;
yourInt ++;

}

Or, if you need both:

yourInt = someNumber;

for (int a = 0; a < aLimit; a ++) {

String stringName = String.valueOf(yourInt);
StringArrayName[a] = stringName;
intArrayName[a] = yourInt;
yourInt ++;

}

I agree with everyone else. For loops are easy to construct, require almost no overhead to run, and are easy to follow when reading code. Elegance in simplicity!

  • There a some problems with your code. 1. of all, nobody uses a blank in a++ while it might work. Don't try to be individual in coding style! 2. What is yourInt, someNumber? They don't exist in the question, and you don't declare or explain them. 3. `casting` is very narrowed defined term in Java. There is no cast from String to Int, because Int isn't a subclass of String. 4. nobody uses `s[a]=String.valueOf (yourInt);`, but `s[a] = "" + yourInt;`. 5. Why the intermediate assignment to stringName? 6. Why violation of coding styles and using StringArrayName[a] instead of stringArrayName[a]? – user unknown Apr 29 '12 at 14:21
  • 7. What a name, stringArrayName! While it is an array of ints as names. 8. no indentation. All those problems hide your simple, but elegant, if applyable, idea. – user unknown Apr 29 '12 at 14:21
0

You can use Collections.sort() and then iterate over the list and collectString.valueOf() each element.

http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#sort%28java.util.List%29

For a Vector, you would first get a List with Collections.list(Enumeration e).

For an array, you would use Arrays.sort() instead of Collections.sort().

http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html#sort%28int%5b%5d%29

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
gpeche
  • 21,974
  • 5
  • 38
  • 51
  • Oh, yes it is. I don't use `Vector` s that much as they are obsolete, so i didn't know they became `List` s. I remembered when you would iterate them with `Vector.elements()` (long ago). – gpeche Sep 01 '10 at 17:05
  • 2
    Vector, Hashtable, StringBuffer: These classes are all somewhat obsolete but folks keep using them. New folks, too. I wonder where they learn that... – Sean Patrick Floyd Sep 01 '10 at 19:36
  • @seanizer:I have never heard StringBuffer to be obsolete.Can you refer to any article? – Emil Sep 02 '10 at 05:37
  • 1
    `StringBuilder` obsoletes `StringBuffer` for most cases. http://download.oracle.com/javase/1.5.0/docs/api/java/lang/StringBuilder.html – gpeche Sep 02 '10 at 06:11
0

Java 8 way, no loops at all:

 // Given
int[] array         = {-5, 8, 3, 10, 25};
// When
String[] actual = Arrays.stream(array)
        .sorted()
        .mapToObj(String::valueOf)
        .toArray(String[]::new);
// Then
String[] expected = {"-5", "3", "8", "10", "25"};

assertArrayEquals(expected, actual);
Maxim Pavlov
  • 195
  • 1
  • 1
  • 10
-2

Arrays.sort(nums); var stringArray = (nums.toString()).split(',').map(String);

user1145927
  • 133
  • 2
  • 13