86

I am wondering if there is a more efficient way of swapping two elements in an Array, than doing something like this:

String temp = arr[1];
arr[1] = arr[2];
arr[2] = temp;

Well, this is obviously not bad or even wrong, but I need to swap very often so I am interested if there are any Libs or something that provide a more efficient way to do this?

6
  • For string? No not really. If you need to do it frequently you might as well just roll your own function once and then its not a hassle Commented Dec 7, 2012 at 15:40
  • 4
    If you can work with List instead of Array, you can use Collections.swap(List, i, j). Commented Dec 7, 2012 at 15:44
  • @Sergio Nakanishi: Interesting Point, maybe I will be able to switch to Collections, however I am not sure if pure Array usage wouldn't be faster? Commented Dec 7, 2012 at 15:47
  • 4
    @Robin: I usually prefer to use ArrayList over array. ArrayList uses an array internally and the overhead of calling a method to manipulate the array is not signicant. The book Effective Java has a more complete reasoning to choose List instead of an array. Commented Dec 7, 2012 at 16:04
  • @SergioNakanishi Thank you for the book tip. I just googled it and it seems pretty nice. Commented Dec 7, 2012 at 16:13

13 Answers 13

46

Nope. You could have a function to make it more concise each place you use it, but in the end, the work done would be the same (plus the overhead of the function call, until/unless HotSpot moved it inline — to help it with that, make the function static final).

Sign up to request clarification or add additional context in comments.

10 Comments

Just for the record, what is the benefit in using static final instead of just static or even none?
@Robin: static tells the compiler and VM (remember, HotSpot is the VM, which does a lot of runtime optimization) that it doesn't have worry about setting up this, which makes it easier to inline the function. final says that it won't be overridden in a subclass. I could easily be wrong about the degree to which HotSpot cares about either of them, really, I'm not au courant with HotSpot's latest wizardry. :-)
I think you can't override a static method.
@Sergio: "I think you can't override a static method." You can, unless it's final, but it's very different from overriding an instance method. Note this error overriding a static final (ideone.com/NuMyv4): "error: foo() in Derived cannot override foo() in Base...overridden method is static,final". That error goes away if it's not final (ideone.com/vnuAk6). It only comes into play if you call the static method via an instance reference, which is an odd thing to do. The method called is determined at compile-time, from the type of the ref: ideone.com/yXDgpa.
Technically, static methods in sub classes are not overridden. They are hidden.
|
35

This should make it seamless:

public static final <T> void swap (T[] a, int i, int j) {
  T t = a[i];
  a[i] = a[j];
  a[j] = t;
}

public static final <T> void swap (List<T> l, int i, int j) {
  Collections.<T>swap(l, i, j);
}

private void test() {
  String [] a = {"Hello", "Goodbye"};
  swap(a, 0, 1);
  System.out.println("a:"+Arrays.toString(a));
  List<String> l = new ArrayList<String>(Arrays.asList(a));
  swap(l, 0, 1);
  System.out.println("l:"+l);
}

1 Comment

this works well , thanks . note that this requires an array of objects so if you get on of those weird compile time errors make sure your using Integer[] array instead of int[] array .
20

If you're swapping numbers and want a concise way to write the code without creating a separate function or using a confusing XOR hack, I find this is much easier to understand and it's also a one liner.

public static void swap(int[] arr, int i, int j) {
    arr[i] = (arr[i] + arr[j]) - (arr[j] = arr[i]);
}

What I've seen from some primitive benchmarks is that the performance difference is basically negligible as well.

This is one of the standard ways for swapping array elements without using a temporary variable, at least for integers.

2 Comments

but arr[i] + arr[j] may overflow
@ChaojunZhong that should not be an issue. The new [i] will be calculated fine when the other number is subtracted. Try it in an IDE
14

If you want to swap string. it's already the efficient way to do that.

However, if you want to swap integer, you can use XOR to swap two integers more efficiently like this:

int a = 1; int b = 2; a ^= b; b ^= a; a ^= b;

9 Comments

What tests did you use to benchmark this and what were the speed improvements?
@bhuang3 - please amend your post explaining why the Java compiler does not perform this optimization. I of course suspect it does hence the DV.
@djechlin I don't consider compiler optimization.. I'm just talking about programming.
That's far longer, more confusing, harder to read and takes more lines of code. I suppose it's more efficient solely with regard to the resource of number of variables declared on the stack but there is no reason to believe the OP was asking for optimization along this resource so DV stands...
@Robin you're welcome, however, just as djechlin says, this way is hard to understand an read, it's just a programming tricky, by the way, if the two integers point to the same address, it may have some problems, but in java, the memory allocation is handled by JVM, so it hard to say if this way is practical or not.
|
7

inplace swapping (incase you already didn't know) can save a bit of space by not creating a temp variable.

arr[i] = arr[i] + arr[j];
arr[j] = arr[i] - arr[j];
arr[i] = arr[i] - arr[j];

Comments

5

Use Collections.swap and Arrays.asList:

Collections.swap(Arrays.asList(arr), i, j);

3 Comments

This will not work if the type in the array is primitive.Arrays.asList(int[]) will convert it to a list of int[].
Can I know why it will not work for primitive types. Actually its not working for me need to know the reason for this.
@AkhilkumarAmarneni Array.asList accepts an array of Objects. And it takes the int[] argument as a single Object and returns a List<int[]> of single element.
2

Incredibly late to the party (my apologies) but a more generic solution than those provided here can be implemented (will work with primitives and non-primitives alike):

public static void swap(final Object array, final int i, final int j) {
    final Object atI = Array.get(array, i);
    Array.set(array, i, Array.get(array, j));
    Array.set(array, j, atI);
}

You lose compile-time safety, but it should do the trick.

Note I: You'll get a NullPointerException if the given array is null, an IllegalArgumentException if the given array is not an array, and an ArrayIndexOutOfBoundsException if either of the indices aren't valid for the given array.

Note II: Having separate methods for this for every array type (Object[] and all primitive types) would be more performant (using the other approaches given here) since this requires some boxing/unboxing. But it'd also be a whole lot more code to write/maintain.

Comments

1

Try this:

    int lowIndex = 0;
    int highIndex = elements.length-1;

    while(lowIndex < highIndex) {
        T lowVal = elements[lowIndex];
        T highVal = elements[highIndex];
        elements[lowIndex] = highVal;
        elements[highIndex] = lowVal;

        lowIndex += 1;
        highIndex -=1;
    }

1 Comment

What question does this try to answer? Why would this be preferable?
1

Solution for object and primitive types:

public static final <T> void swap(final T[] arr, final int i, final int j) {
    T tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
public static final void swap(final boolean[] arr, final int i, final int j) {
    boolean tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
public static final void swap(final byte[] arr, final int i, final int j) {
    byte tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
public static final void swap(final short[] arr, final int i, final int j) {
    short tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
public static final void swap(final int[] arr, final int i, final int j) {
    int tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
public static final void swap(final long[] arr, final int i, final int j) {
    long tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
public static final void swap(final char[] arr, final int i, final int j) {
    char tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
public static final void swap(final float[] arr, final int i, final int j) {
    float tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}
public static final void swap(final double[] arr, final int i, final int j) {
    double tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

1 Comment

This should be part of the standard library IMO
0

first of all you shouldn't write for (int k = 0; k **<** data.length **- 1**; k++)because the < is until the k is smaller the length -1 and then the loop will run until the last position in the array and won't get the last place in the array; so you can fix it by two ways: 1: for (int k = 0; k <= data.length - 1; k++) 2: for (int k = 0; k < data.length; k++) and then it will work fine!!! and to swap you can use: to keep one of the int's in another place and then to replace

int x = data[k]
data[k] = data[data.length - 1]
data[data.length - 1] = x;

because you don't want to lose one of the int's!!

1 Comment

What question does this try to answer?
0

This is just "hack" style method:

int d[][] = new int[n][n];

static int swap(int a, int b) {
  return a;
}
...

in main class --> 

d[i][j + 1] = swap(d[i][j], d[i][j] = d[i][j + 1])

Comments

0
public static final void swap (int[] a, int i, int j) {
    a[i] = a[i] + a[j];
    a[j] = a[i] - a[j];
    a[i] = a[i] - a[j];
}

1 Comment

What's the distinguishing detail over Neel Alex' answer?
-3
public class SwapElements {

public static void main(String[] args) {

    int[] arr1 = new int[5];
    int[] arr2 = {10,20,30,40};

    System.out.println("arr1 Before Swapping " + Arrays.toString(arr1));
    System.out.println("arr2 Before Swapping " + Arrays.toString(arr2));

    int temp[];
    arr1[3] = 5;
    arr1[0] = 2;
    arr1[1] = 3;
    arr1[2] = 6;
    arr1[4] = 10;

    temp = arr1;
    arr1 = arr2;
    arr2 = temp;
    System.out.println("arr1 after Swapping " + Arrays.toString(arr1));
    System.out.println("arr2 after Swapping " + Arrays.toString(arr2));
}

}

1 Comment

This doesn't answer the question. The question was to swap elements of an array. Flipping the references to two arrays does nothing to modify their contents. Not to mention you used the exact same method to switch the arrays as the question was trying to find an alternative to.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.