Search code examples
javajavascriptsplice

Java eqivalent method of "splice(a,b,...)" in JavaScript method


someArray.splice(a,b,...) method in JavaScript adds or removes items to/from array. What could be good and simple solution to implement such method in Java language? Assume we have String[] array.


Solution

  • Here is a Java implementation of the Array.prototype.splice() method as per the JavaScript MDN specification.

      public static <T>T[] splice(final T[] array, int start) {
        if (start < 0)
          start += array.length;
    
        return splice(array, start, array.length - start);
      }
    
      @SuppressWarnings("unchecked")
      public static <T>T[] splice(final T[] array, int start, final int deleteCount) {
        if (start < 0)
          start += array.length;
    
        final T[] spliced = (T[])Array.newInstance(array.getClass().getComponentType(), array.length - deleteCount);
        if (start != 0)
          System.arraycopy(array, 0, spliced, 0, start);
    
        if (start + deleteCount != array.length)
          System.arraycopy(array, start + deleteCount, spliced, start, array.length - start - deleteCount);
    
        return spliced;
      }
    
      @SuppressWarnings("unchecked")
      public static <T>T[] splice(final T[] array, int start, final int deleteCount, final T ... items) {
        if (start < 0)
          start += array.length;
    
        final T[] spliced = (T[])Array.newInstance(array.getClass().getComponentType(), array.length - deleteCount + items.length);
        if (start != 0)
          System.arraycopy(array, 0, spliced, 0, start);
    
        if (items.length > 0)
          System.arraycopy(items, 0, spliced, start, items.length);
    
        if (start + deleteCount != array.length)
          System.arraycopy(array, start + deleteCount, spliced, start + items.length, array.length - start - deleteCount);
    
        return spliced;
      }
    

    The following JUnit code tests this implementation:

    @Test
      public void testSplice() {
        final String[] array = new String[] {"a", "b", "c", "d", "e", "f"};
    
        Assert.assertArrayEquals(new String[] {"c", "d", "e", "f"}, Arrays.splice(array, 0, 2));
        Assert.assertArrayEquals(new String[] {"a", "d", "e", "f"}, Arrays.splice(array, 1, 2));
        Assert.assertArrayEquals(new String[] {"a", "b", "e", "f"}, Arrays.splice(array, 2, 2));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "f"}, Arrays.splice(array, 3, 2));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "d"}, Arrays.splice(array, 4, 2));
        try {
          Arrays.splice(array, 5, 2);
          Assert.fail("Expected ArrayIndexOutOfBoundsException");
        }
        catch (final ArrayIndexOutOfBoundsException e) {
        }
    
        try {
          Arrays.splice(array, -2, 3);
          Assert.fail("Expected ArrayIndexOutOfBoundsException");
        }
        catch (final ArrayIndexOutOfBoundsException e) {
        }
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "d"}, Arrays.splice(array, -2, 2));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "f"}, Arrays.splice(array, -3, 2));
        Assert.assertArrayEquals(new String[] {"a", "b", "e", "f"}, Arrays.splice(array, -4, 2));
        Assert.assertArrayEquals(new String[] {"a", "d", "e", "f"}, Arrays.splice(array, -5, 2));
        Assert.assertArrayEquals(new String[] {"c", "d", "e", "f"}, Arrays.splice(array, -6, 2));
        try {
          Arrays.splice(array, -7, 2);
          Assert.fail("Expected ArrayIndexOutOfBoundsException");
        }
        catch (final ArrayIndexOutOfBoundsException e) {
        }
    
        Assert.assertArrayEquals(new String[] {}, Arrays.splice(array, 0));
        Assert.assertArrayEquals(new String[] {"a"}, Arrays.splice(array, 1));
        Assert.assertArrayEquals(new String[] {"a", "b"}, Arrays.splice(array, 2));
        Assert.assertArrayEquals(new String[] {"a", "b", "c"}, Arrays.splice(array, 3));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "d"}, Arrays.splice(array, 4));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "d", "e"}, Arrays.splice(array, 5));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "d", "e", "f"}, Arrays.splice(array, 6));
        try {
          Arrays.splice(array, 7);
          Assert.fail("Expected ArrayIndexOutOfBoundsException");
        }
        catch (final ArrayIndexOutOfBoundsException e) {
        }
    
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "d", "e"}, Arrays.splice(array, -1));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "d"}, Arrays.splice(array, -2));
        Assert.assertArrayEquals(new String[] {"a", "b", "c"}, Arrays.splice(array, -3));
        Assert.assertArrayEquals(new String[] {"a", "b"}, Arrays.splice(array, -4));
        Assert.assertArrayEquals(new String[] {"a"}, Arrays.splice(array, -5));
        Assert.assertArrayEquals(new String[] {}, Arrays.splice(array, -6));
        try {
          Arrays.splice(array, -7);
          Assert.fail("Expected NegativeArraySizeException");
        }
        catch (final NegativeArraySizeException e) {
        }
    
        Assert.assertArrayEquals(new String[] {"x", "y", "z", "c", "d", "e", "f"}, Arrays.splice(array, 0, 2, "x", "y", "z"));
        Assert.assertArrayEquals(new String[] {"a", "x", "y", "z", "d", "e", "f"}, Arrays.splice(array, 1, 2, "x", "y", "z"));
        Assert.assertArrayEquals(new String[] {"a", "b", "x", "y", "z", "e", "f"}, Arrays.splice(array, 2, 2, "x", "y", "z"));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "x", "y", "z", "f"}, Arrays.splice(array, 3, 2, "x", "y", "z"));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "d", "x", "y", "z"}, Arrays.splice(array, 4, 2, "x", "y", "z"));
        try {
          Arrays.splice(array, 5, 2, "x", "y", "z");
          Assert.fail("Expected ArrayIndexOutOfBoundsException");
        }
        catch (final ArrayIndexOutOfBoundsException e) {
        }
    
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "d", "x", "y", "z"}, Arrays.splice(array, -2, 2, "x", "y", "z"));
        Assert.assertArrayEquals(new String[] {"a", "b", "c", "x", "y", "z", "f"}, Arrays.splice(array, -3, 2, "x", "y", "z"));
        Assert.assertArrayEquals(new String[] {"a", "b", "x", "y", "z", "e", "f"}, Arrays.splice(array, -4, 2, "x", "y", "z"));
        Assert.assertArrayEquals(new String[] {"a", "x", "y", "z", "d", "e", "f"}, Arrays.splice(array, -5, 2, "x", "y", "z"));
        Assert.assertArrayEquals(new String[] {"x", "y", "z", "c", "d", "e", "f"}, Arrays.splice(array, -6, 2, "x", "y", "z"));
        try {
          Arrays.splice(array, -7, 2, "x", "y", "z");
          Assert.fail("Expected ArrayIndexOutOfBoundsException");
        }
        catch (final ArrayIndexOutOfBoundsException e) {
        }
      }
    

    Edit: As @denys-séguret pointed out correctly, this implementation differs from the JavaScript spec as it does not mutate/modify the original array. Instead, this implementation returns a new array instance.

    Edit: This implementation is available with the following maven artifact, at the given maven repo:

    <project>
      ...
      <dependencies>
        <dependency>
          <groupId>org.safris.commons</groupId>
          <artifactId>commons-lang</artifactId>
          <version>1.6.4</version>
        </dependency>
      </dependencies>
      ...
      <repositories>
        <repository>
          <id>mvn.repo.safris.org</id>
          <url>http://mvn.repo.safris.org/m2</url>
        </repository>
      </repositories>
      ...
    </project>