Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 49 additions & 28 deletions src/main/java/com/dashjoin/jsonata/Functions.java
Original file line number Diff line number Diff line change
Expand Up @@ -1950,38 +1950,59 @@ public static List sort(List arr, Object comparator) {
return arr;
}

List result = new ArrayList<>(arr);

if (comparator != null) {
Comparator comp = new Comparator() {

@Override
public int compare(Object o1, Object o2) {
try {
Boolean swap = toBoolean(funcApply(comparator, Arrays.asList(o1, o2)));
if (swap == null)
return 0;
if (swap)
return 1;
else
return -1;
} catch (Throwable e) {
// TODO Auto-generated catch block
//e.printStackTrace();
throw new RuntimeException(e);
}
}

};
if (comparator instanceof Comparator)
result.sort((Comparator)comparator);
else
result.sort((Comparator)comp);
} else {
result.sort(null);
if (comparator instanceof Comparator) {
List sorted = new ArrayList<>(arr);
sorted.sort((Comparator) comparator);
return sorted;
}

Object[] sorted = arr.toArray();
Object[] buffer = new Object[sorted.length];
mergeSort(sorted, buffer, 0, sorted.length - 1, comparator);
List result = new ArrayList<>(sorted.length);
Collections.addAll(result, sorted);
return result;
}

return result;
List sorted = new ArrayList<>(arr);
sorted.sort(null);
return sorted;
}

private static void mergeSort(Object[] sorted, Object[] buffer, int lo, int hi, Object jsonataComparator) {
if (lo >= hi) {
return;
}
int mid = (lo + hi) / 2;
mergeSort(sorted, buffer, lo, mid, jsonataComparator);
mergeSort(sorted, buffer, mid + 1, hi, jsonataComparator);
merge(sorted, buffer, lo, mid, hi, jsonataComparator);
}

private static void merge(Object[] sorted, Object[] buffer, int lo, int mid, int hi, Object jsonataComparator) {
int left = lo, right = mid + 1, writePos = lo;

while (left <= mid && right <= hi) {
boolean swap;
try {
Boolean sw = toBoolean(funcApply(jsonataComparator, Arrays.asList(sorted[left], sorted[right])));
swap = Boolean.TRUE.equals(sw);
} catch (Throwable e) {
throw new RuntimeException(e);
}

if (swap) {
buffer[writePos++] = sorted[right++];
} else {
buffer[writePos++] = sorted[left++];
}
}
while (left <= mid) buffer[writePos++] = sorted[left++];
while (right <= hi) buffer[writePos++] = sorted[right++];

System.arraycopy(buffer, lo, sorted, lo, hi - lo + 1);
}

/**
Expand Down
16 changes: 15 additions & 1 deletion src/test/java/com/dashjoin/jsonata/ArrayTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
import static java.util.Arrays.asList;
import static java.util.Map.of;
import static org.junit.jupiter.api.Assertions.assertEquals;

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

public class ArrayTest {
Expand Down Expand Up @@ -83,4 +86,15 @@ public void testSortTypes() {
e = jsonata("[{'value': 'b'}, {'value': 'a'}] ^(<value).value");
Assertions.assertEquals(List.of("a", "b"), e.evaluate(null));
}

//This test only shows the problem on a large array. Experiments show an error on element 81.
@Test
public void testSortLargeArray() throws IOException {
Object data = new ObjectMapper().readValue(new File("test/ISSUE-114-largeArrayToSort.json"), Object.class);
Object result = new ObjectMapper().readValue(new File("test/ISSUE-114-largeArrayResult.json"), Object.class);

var expression = jsonata("$sort($, function($l, $r){$l.*.rank < $r.*.rank})");
Object evaluate = expression.evaluate(data);
Assertions.assertEquals(result, evaluate);
}
}
Loading
Loading