0

Suppose I have the following String: "10 30 20 12 34". Now I want to rotate the String but keep the first and last integers fixed. So I should get the 3 outputs should be as follows:

10 20 30 12 34

10 30 12 20 34

10 12 20 30 34

Now, I am trying to first convert the String into an int[] array such that it looks like [10, 30,20, 12, 34] and then create another array, get each element of the original array and insert them in the new array.

This is what I have so far:

String[] arr1 = tree.getPreOrder().split(" ");
int[] arr2 = new int[5];
arr2[0] = Integer.parseInt(arr1[0]);
arr2[1] = Integer.parseInt(arr1[3]);
arr2[2] = Integer.parseInt(arr1[2]);
arr2[3] = Integer.parseInt(arr1[1]);
arr2[4] = Integer.parseInt(arr1[4]);

My issue is, how do I now convert arr2 into the format 10 12 20 30 34. I tried to use join() but it doesn't work.

Also, is there a simpler way to do what I'm trying to do as currently, I am hard coding those values.

Thanks

UPDATE I created a method which basically rotates the middle values now. However, I got into an issue where one randomly generated String was the same as the original and I would like to avoid that. I'm basically trying to generate only exactly 3 variations of the original string if that helps. Here's my updated code:

static String randomizeAnswer(String ans) {
    String[] arr = ans.split(" ");

    int arraySize = arr.length;

    String firstElement = arr[0];
    String lastElement = arr[arraySize - 1];

    String[] arr2 = new String[arraySize - 2];

    String arr3[] = new String[arraySize];

    arr3[0] = firstElement;
    for (int i = 0; i < arraySize - 2; i++) {
        arr2[i] = arr[i + 1];
    }

    Collections.shuffle(Arrays.asList(arr2));

    for (int j = 0; j < arr2.length; j++) {
        arr3[j + 1] = arr2[j];
    }
    arr3[arraySize - 1] = lastElement;

    return String.join(" ", arr3);
}

for int(i = 0; i<3; i++){
    System.out.println(randomizeAnswer("10 30 20 12 34"));
}

UPDATE 2 I eventually managed to make a solution which works but the answer by @WJS below is much better.

static String randomizeAnswer(String ans) {
        String[] arr = ans.split(" ");

        int arraySize = arr.length;

        String firstElement = arr[0];
        String lastElement = arr[arraySize - 1];

        String[] arr2 = new String[arraySize - 2];

        String arr3[] = new String[arraySize];

        arr3[0] = firstElement;
        for (int i = 0; i < arraySize - 2; i++) {
            arr2[i] = arr[i + 1];
        }

        Collections.shuffle(Arrays.asList(arr2));

        for (int j = 0; j < arr2.length; j++) {
            arr3[j + 1] = arr2[j];
        }
        arr3[arraySize - 1] = lastElement;

        return String.join(" ", arr3);
        
    }

    static String[] generateAnswers(String ans) {
        String[] answers = new String[5];
        answers[0] = ans;
        answers[4] = "None of the answers are correct";

        for (int x = 0; x < 3; x++) {

            while (true) {
                String randomAns = randomizeAnswer(ans);
                if (Arrays.stream(answers).anyMatch(randomAns::equals)) {
                    continue;
                } else {
                    answers[x+1] = randomAns;
                    break;
                }
            }
        }

        return answers;
    }
nTuply
  • 1,364
  • 19
  • 42
  • you want to rotate, not shuffle – Walter Tross Oct 15 '20 at 13:23
  • @WalterTross I didn't know that was a term, I edited my question now. Thanks. – nTuply Oct 15 '20 at 13:25
  • https://stackoverflow.com/questions/38425623/java-join-array-of-primitives-with-separator – Eklavya Oct 15 '20 at 13:49
  • Do you want to know how to rotate the array or just concatenate the results into a string? – WJS Oct 15 '20 at 13:54
  • @WJS I actually want to know how to rotate as well. I realised I could just make `arr2` a String array and simply use a for loop to append values into it. However, the middle rotate is what I'm more interested in as I am trying to figure out a way to get 3 other permutations of the original string by rotating the middle values. – nTuply Oct 15 '20 at 13:59
  • @WJS I added my updated code just now in the OP. – nTuply Oct 15 '20 at 14:01

6 Answers6

1

Convert the array to ints. Note that the string values could be rotated without parsing to an int.

String str = "10 30 20 12 34";

int[] vals = Arrays.stream(str.split("\\s+"))
        .mapToInt(Integer::parseInt).toArray();

The range to rotate

int start = 1;
int end = 4; // exclusive

An array to save the rotated array of values.

String[] results = new String[end - start];

And now rotating them, converting to a string and storing. Note that the previously rotated array needs to be fed back into the method. But that array is not changed because it is copied in the rotate method.

for (int i = 0; i < end - start; i++) {
    vals = rotate(vals, start, end);
    // convert to String - can't use join since these are not strings.
    // this just streams the results, converts to a string, and joins them into
    // a single string.
    results[i] =
            Arrays.stream(vals).mapToObj(v -> Integer.toString(v))
                    .collect(Collectors.joining(" "));
}

for (String rotated : results) {
    System.out.println(rotated);
}

prints

10 20 12 30 34
10 12 30 20 34
10 30 20 12 34

This simply rotates the array one cell to the left within the specified range. It first makes a copy of the original array. Note the end is exclusive.

public static int[] rotate(int[] arr, int start, int end) {
    arr = Arrays.copyOf(arr, arr.length);
    int v = arr[start];
    for (int i = start; i < end-1; i++) {
      arr[i] = arr[i+1];
    }
    arr[end-1] = v;
    return arr;
}
WJS
  • 36,363
  • 4
  • 24
  • 39
  • Beautiful solution. I just coded a solution from scratch which works, but the `rotate` function is brilliant and makes the solution much simpler as I had 2 big functions. Thanks for this solution! I added my solution to an edit of my question above just for completeness. – nTuply Oct 15 '20 at 14:35
  • Thanks! Note that I did not add any checks to ensure the range did not exceed the size of the array so it will throw an exception if that occurs. Of course you can add that at your leisure. – WJS Oct 15 '20 at 14:37
  • Sure, adding the check shouldn't be a problem now. Just out of curiosity, can you please check my solution in the OP (UPDATE 2) and maybe let me know if it's actually a kind of efficient solution? I realise it's probably a hacky way but curious about it nonetheless – nTuply Oct 15 '20 at 14:39
  • In your updated version, you cannot guarantee it will produce the desired output because `Collections.shuffle` is a random operation so you can get repeated shuffles. To see this do about 100 iterations of the method and see how often the original is returned. Rotating is a much more controlled and predictable operation than shuffling. – WJS Oct 15 '20 at 15:46
1

Here's my two cents using Java Streams.

private static int[] rotate(int[] array, int count) {
    if (array.length >= 0 && array.length <= 2) {
        return array;
    }

    return IntStream.range(0, array.length)
        .map(i -> (i == 0 || i == array.length - 1) ? i : (i - 1 + count) % (array.length - 2) + 1)
        .map(i -> array[i])
        .toArray();
}

This rotates the given array count positions to the right, but leaves the first and last indexes unharmed. For example, when count = 1, the array [10, 30, 20, 12, 34] becomes [10, 12, 30, 20, 34].


If you want to generate an n number of random sequences, you could use the snippet below. This generates arrays which are not equal to the original array.

int array = { … };
int n = 2;
ThreadLocalRandom.current().ints(n, 1, array.length - 2)
    .mapToObj(randomInt -> rotate(array, randomInt))
    .forEach(result -> System.out.println(Arrays.toString(result)));
    // Or, if you want to convert it back to a String:
    //.collect(Collectors.mapping(String::valueOf, Collectors.joining(" ")));

Collections::shuffle

Of course, you can also simply shuffle the elements minus the first and last ones using Collections::shuffle and List::subList. This method is generic, so it really does not matter whether the elements are actually integers or not. For instance, a List<String> is yielded with Arrays.asList("10 30 20 12 34".split(" ")).

public static <T> List<T> shuffleMid(List<T> list) {
    List<T> newList = new ArrayList<>(list);
    do {
        Collections.shuffle(newList.subList(1, newList.size() - 1));
    } while (newList.equals(list)); // Make sure it is unequal to the original
    return newList;
}

The do-while loop makes sure the shuffled list is not equal to the original list. This may be a naive implementation.

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
1

Another example:

  public static void main(String[] args) {
    String treePreOrder = "10 30 20 12 34";    
    String rot1 = rotateMiddle(treePreOrder);
    String rot2 = rotateMiddle(rot1);

    System.out.println(treePreOrder);
    System.out.println(rot1);
    System.out.println(rot2);
  }

  public static String rotateMiddle(String values) {
    String[] arr = values.split(" ");
    if (arr.length >= 4) {
      String temp = arr[1];
      for(int i=1; i<=(arr.length-3); i++) {
        arr[i] = arr[i+1];
      }
      arr[arr.length-2] = temp;
    }
    return String.join(" ", arr);
  }

Output:

10 30 20 12 34
10 20 12 30 34
10 12 30 20 34
Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
0

To rotate the elements (except the first and last elements) you can use this:

    1. use another helping array:
        String in = "10 30 20 12 34";
        String[] arr_in = in.split(" ");
        String[] arr_out = new String[arr_in.length];
        
        arr_out[0] = arr_in[0];
        arr_out[arr_out.length-1] = arr_in[arr_in.length-1];
        
        for(int i=arr_in.length-2, j=1;  i>0;  i--,j++)
        {
            arr_out[j] = arr_in[i];
        }
        
        // print:
        for(int i=0; i<arr_out.length;i++)
        {
            System.out.println(arr_out[i]);
        }
    1. in place :
    
    public static void main(String[] args) {
        
        String in = "10 30 20 12 34";
        String[] arr = in.split(" ");
        
        String tmp;
        for(int i=arr_in.length-2, j=1;  i>(arr_in.length/2);   i--,j++)
        {
            tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
        }
        
        // print:
        for(int i=0; i<arr.length;i++)
        {
            System.out.println(arr[i]);
        }
        
        
    }

ibra
  • 1,164
  • 1
  • 11
  • 26
0
    String[] array = new String[5];
    for(int i = 0; i < 5; i++)
        array[i] = i + 1 + "";
     //array[0] = 1, array[1] = 2, array[3] = 3, array[4] = 4, array[5] = 5

    int first = 0;
    int last = array.length - 1;
    
    for(int i = 1; i < array.length / 2; i++){
        first = i;
        last = array.length - i - 1;
        String aux = array[first];
        array[first] = array[last];
        array[last] = aux;
        first++;
        last--;
    }
    
    for(int i = 0; i < array.length; i++)
        System.out.print(array[i] + " ");

The output will be: 1 4 3 2 5

ABC
  • 595
  • 2
  • 5
  • 20
0

There most definitely is a better way to leverage other APIs in the JDK... but here is what I came up with.

// shifts by [direction] spaces (-ve and +ve) for left/right. So far so good with not throwing IndexOutOfBoundsExceptions :)
private static int[] shift(int[] values, int direction) {

    int[] result = new int[values.length];
    for (int i = 0; i < result.length; i++) {
        result[i] = values[(values.length + (i + direction % values.length)) % values.length];
    }
    return result;
}

public static void main(String[] args) {
    int[] values = new int[]{101, 1, 2, 3, 100};
    int[] middleValues = Arrays.copyOfRange(values, 1, values.length-1);
    
    int[][] allCombos = new int[middleValues.length][values.length];
    
    int shiftPtr = 0;
    for (int[] row : allCombos) {
        row[0] = values[0];
        row[row.length-1] = values[values.length-1];
        int[] shifted = shift(middleValues, shiftPtr);
        for (int i = 0; i < middleValues.length; i++) {
            row[i + 1] = shifted[i];                
        }
        shiftPtr++;
        // and print out to test...
        System.out.println(Arrays.toString(row));
    }                                                
    
}

And you end up with this output....

> [101, 1, 2, 3, 100]  
> [101, 2, 3, 1, 100]
> [101, 3, 1, 2, 100]