如何从嵌套的 String 数组的 ArrayList 中删除相交的 String[] 数组?
How to remove intersecting String[] arrays from a nested ArrayList of String arrays?
假设我有一个
ArrayList<ArrayList<String[]>>
名为 ListToProcess
的变量,在每个 arrayList 中我有以下 ArrayLists of String[]
:
String[] arr1 = {"1","2","3"};
String[] arr2 = {"7","5","3"};
String[] arr3 = {"8","2","6"};
String[] arr4 = {"0","4","9"};
ArrayList<String[]> arrString1
包含 arr1
和 arr2
并且 ArrayList<String[]> arrString1
包含 arr3
和 arr4
我想以这样的方式处理 ListToProcess
以删除 arr2
& arr3
因为与 arr1
相交(或保留 arr2
并删除 arr1
和arr3
...) 从它。
我尝试通过以下方法将 ListToProcess
展平为 List<String[]>
并删除相交的元素 removeIntersectingArrays
List<String[]> flatList =
partitionsOfClustersIds.stream()
.flatMap(ListToProcess::stream)
.collect(Collectors.toList());
ArrayList<String[]> flattenedArrayElements= new ArrayList<String[]>(flatList);
flattenedArrayElements= removeIntersectingArrays(flattenedArrayElements);
removeIntersectingArrays
方法如下:
Public static ArrayList<String[]> removeIntersectingArrays(ArrayList<String[]> totalArrays) {
List<Integer> idx = new ArrayList<Integer>();
for (int i = 0; i < totalArrays.size(); i++)
for (int j = i + 1; j < totalArrays.size(); j++) {
String[] tmpArr = totalArrays.get(j);
if (Arrays.stream(totalArrays.get(i)).distinct().filter(x -> Arrays.stream(tmpArr).anyMatch(y -> y.equals(x))).toArray().length != 0) {
idx.add(j);
}
}
Collections.reverse(idx);
for (int k : idx)
totalArrays.remove(k); // this line raises an indexOutOfBound exception
return totalArrays;
}
但是我收到 indexOutOfBound
错误,知道如何解决这个问题吗?
不要使用具体实现(如ArrayList
)而不是抽象(如List
)当它不给你买任何东西的时候。通常是这种情况,唯一的例外是当您需要能够调用未在 List
接口中定义并且只能通过 ArrayList class
访问的方法时,例如 ensureCapacity()
或 trimToSize()
.
旁注:
Collectors.toList()
默认使用 ArrayList
作为 List
接口的实现;
- 每当您需要具体实施时使用
Collector.toCollection()
。
removeIntersectingArrays()
方法的时间复杂度通过维护一个 HashSet
来降低,该 HashSet
存储之前遇到的所有数组中的字符串。每个数组都必须根据这个集合进行检查。
public static void main(String[] args) {
List<List<String[]>> list= List.of(
List.of(new String[]{"1","2","3"},
new String[]{"7","5","3"}),
List.of(new String[]{"8","2","6"},
new String[]{"0","4","9"})
);
List<String[]> flatList = flatten(list);
for (String[] arr: removeIntersectingArrays(flatList)) {
System.out.println(Arrays.toString(arr));
}
}
public static List<String[]> flatten(List<List<String[]>> source) {
return source.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
}
public static List<String[]> removeIntersectingArrays(List<String[]> source) {
List<String[]> result = new ArrayList<>();
Set<String> seen = new HashSet<>();
for (String[] arr: source) {
boolean notSeenPreviously = true;
for (String next: arr) {
if (seen.contains(next)) {
notSeenPreviously = false;
break;
}
}
if (notSeenPreviously) {
result.add(arr);
Collections.addAll(seen, arr);
}
}
return result;
}
输出(arr2
& arr3
被移除)
[1, 2, 3]
[0, 4, 9]
我发现从要删除的元素的索引列表中删除重复项解决了这个问题:这样做:
...
// remove duplicates
List<Integer> idxWithoutDuplicates = new ArrayList<>(
new LinkedHashSet<>(idx));
Collections.reverse(idxWithoutDuplicates); ...
解决了我的问题。
UPDATE:或其他解决方案是:检查索引是否已通过例如此衬里添加到上面的 idx
数组中:
...
if (!Arrays.asList(idx).contains(j))
idx.add(j);...
假设我有一个
ArrayList<ArrayList<String[]>>
名为 ListToProcess
的变量,在每个 arrayList 中我有以下 ArrayLists of String[]
:
String[] arr1 = {"1","2","3"};
String[] arr2 = {"7","5","3"};
String[] arr3 = {"8","2","6"};
String[] arr4 = {"0","4","9"};
ArrayList<String[]> arrString1
包含 arr1
和 arr2
并且 ArrayList<String[]> arrString1
包含 arr3
和 arr4
我想以这样的方式处理 ListToProcess
以删除 arr2
& arr3
因为与 arr1
相交(或保留 arr2
并删除 arr1
和arr3
...) 从它。
我尝试通过以下方法将 ListToProcess
展平为 List<String[]>
并删除相交的元素 removeIntersectingArrays
List<String[]> flatList =
partitionsOfClustersIds.stream()
.flatMap(ListToProcess::stream)
.collect(Collectors.toList());
ArrayList<String[]> flattenedArrayElements= new ArrayList<String[]>(flatList);
flattenedArrayElements= removeIntersectingArrays(flattenedArrayElements);
removeIntersectingArrays
方法如下:
Public static ArrayList<String[]> removeIntersectingArrays(ArrayList<String[]> totalArrays) {
List<Integer> idx = new ArrayList<Integer>();
for (int i = 0; i < totalArrays.size(); i++)
for (int j = i + 1; j < totalArrays.size(); j++) {
String[] tmpArr = totalArrays.get(j);
if (Arrays.stream(totalArrays.get(i)).distinct().filter(x -> Arrays.stream(tmpArr).anyMatch(y -> y.equals(x))).toArray().length != 0) {
idx.add(j);
}
}
Collections.reverse(idx);
for (int k : idx)
totalArrays.remove(k); // this line raises an indexOutOfBound exception
return totalArrays;
}
但是我收到 indexOutOfBound
错误,知道如何解决这个问题吗?
不要使用具体实现(如ArrayList
)而不是抽象(如List
)当它不给你买任何东西的时候。通常是这种情况,唯一的例外是当您需要能够调用未在 List
接口中定义并且只能通过 ArrayList class
访问的方法时,例如 ensureCapacity()
或 trimToSize()
.
旁注:
Collectors.toList()
默认使用ArrayList
作为List
接口的实现;- 每当您需要具体实施时使用
Collector.toCollection()
。
removeIntersectingArrays()
方法的时间复杂度通过维护一个 HashSet
来降低,该 HashSet
存储之前遇到的所有数组中的字符串。每个数组都必须根据这个集合进行检查。
public static void main(String[] args) {
List<List<String[]>> list= List.of(
List.of(new String[]{"1","2","3"},
new String[]{"7","5","3"}),
List.of(new String[]{"8","2","6"},
new String[]{"0","4","9"})
);
List<String[]> flatList = flatten(list);
for (String[] arr: removeIntersectingArrays(flatList)) {
System.out.println(Arrays.toString(arr));
}
}
public static List<String[]> flatten(List<List<String[]>> source) {
return source.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
}
public static List<String[]> removeIntersectingArrays(List<String[]> source) {
List<String[]> result = new ArrayList<>();
Set<String> seen = new HashSet<>();
for (String[] arr: source) {
boolean notSeenPreviously = true;
for (String next: arr) {
if (seen.contains(next)) {
notSeenPreviously = false;
break;
}
}
if (notSeenPreviously) {
result.add(arr);
Collections.addAll(seen, arr);
}
}
return result;
}
输出(arr2
& arr3
被移除)
[1, 2, 3]
[0, 4, 9]
我发现从要删除的元素的索引列表中删除重复项解决了这个问题:这样做:
...
// remove duplicates
List<Integer> idxWithoutDuplicates = new ArrayList<>(
new LinkedHashSet<>(idx));
Collections.reverse(idxWithoutDuplicates); ...
解决了我的问题。
UPDATE:或其他解决方案是:检查索引是否已通过例如此衬里添加到上面的 idx
数组中:
...
if (!Arrays.asList(idx).contains(j))
idx.add(j);...