一种高效的Java列表合并算法
我有两个Java列表(就像在实际的类中一样),每个列表都有编号列表的元素和级别,表示为字符串对象。下面的每一行都是列表中一个单独的字符串。例如,第一个列表可以是:一种高效的Java列表合并算法,java,algorithm,list,arraylist,Java,Algorithm,List,Arraylist,我有两个Java列表(就像在实际的类中一样),每个列表都有编号列表的元素和级别,表示为字符串对象。下面的每一行都是列表中一个单独的字符串。例如,第一个列表可以是: ==level 1== 1.1 2 ==level 2== 1.R4 0 2.0 2 ==level 3== 3.R3 1 4.R5 1 ==level 3== 1.null 2.null 第二种可能是: ==level 1== 1.1 2 ==level 2== 1.R4 0 2.0 2 ==level 3==
==level 1==
1.1 2
==level 2==
1.R4 0
2.0 2
==level 3==
3.R3 1
4.R5 1
==level 3==
1.null
2.null
第二种可能是:
==level 1==
1.1 2
==level 2==
1.R4 0
2.0 2
==level 3==
3.R3 1
4.R5 1
==level 3==
1.null
2.null
列表可以是任意长度,数字后面的值在这里并不重要。目标是合并匹配级别的列表。例如,上面两个列表的合并将是:
==level 1==
1.1 2
==level 2==
1.R4 0
2.0 2
==level 3==
1.null
2.null
3.R3 1
4.R5 1
两个列表的匹配级别中的数字永远不会相同,因此不需要进行检查。我还相信,这些数字将永远是连续的。这是我到目前为止所做的,但它并没有涵盖所有情况,特别是当合并只发生在一个级别的开始或结束时。这看起来也很不愉快。模板行和行是两个列表
for(int x=0; x < lines.size();x++){
for(int y=0; y < tempLines.size();y++){
if(tempLines.get(y).equals(lines.get(x)) && !(tempLines.get(y).equals("\n"))&& !(lines.get(x).equals("\n"))){
int a=y+1;
int b=x+1;
while(!(tempLines.get(a).equals("\n"))){
while(!(lines.get(b).equals("\n"))){
if(Integer.valueOf(tempLines.get(a).charAt(0))==(Integer.valueOf(tempLines.get(a).charAt(0))-1))
lines.add(b,tempLines.get(a));
}
}
}
}
}
for(int x=0;x
有人能帮忙吗?您可以将集合按级别拆分,并使用Apache Commons集合
Collection a = createCollection();
Collection b = createCollection();
Collection c = CollectionUtils.union(a,b);
您可以按级别拆分集合并使用Apache Commons集合
Collection a = createCollection();
Collection b = createCollection();
Collection c = CollectionUtils.union(a,b);
我通常通过使用
Map
处理这些问题。可以使用其他集合,例如列表,但我发现使用映射的代码更容易阅读(并且可能不是性能问题,除非列表中有数百万个元素)
在这种情况下,我将有一个映射
,用于保持条目的正确顺序。这样的映射将作为值存储在另一个映射中,其中键是级别号。我将使用TreeMap
作为实现类,因为它根据条目的键对条目进行排序
Map<Integer,Map<Integer,String>> map = new TreeMap<>();
int level=0; //current level
for (String line:templines) {
if (line.startsWith("==level ")) {
level=Integer.valueOf(line.substring(7).replace("==","").trim());
if (map.get(level)==null) map.put(level,new TreeMap<>());
} else if (line.length>0) {
int pos = line.indexOf('.');
if (pos>0) {
int n = Integer.valueOf(line.substring(0,pos));
line=line.substring(pos+1);
map.get(level).put(n,line);
}
}
}
Map Map=newtreemap();
智力水平=0//当前水平
用于(字符串行:模板行){
if(line.startsWith(“==level”){
level=Integer.valueOf(line.substring(7).replace(“==”,”).trim());
if(map.get(level)==null)map.put(level,newtreemap());
}else if(行长度>0){
int pos=行索引('.');
如果(位置>0){
int n=整数.valueOf(行.子字符串(0,pos));
行=行子串(位置+1);
地图。获取(水平)。放置(n,线);
}
}
}
一旦我有了地图,我会迭代它并将值保存在另一个列表中
List<String> merged = new ArrayList<String>();
for (Map.Entry<Integer,Map<Integer,String>> entry:map.entrySet()) {
list.add("==level "+entry.getKey()+"==");
for (String line:entry.getValue().values()) {
list.add(line);
}
}
List merged=new ArrayList();
对于(Map.Entry:Map.entrySet()){
list.add(“==level”+entry.getKey()+“==”);
for(字符串行:entry.getValue().values()){
列表。添加(行);
}
}
我通常使用Map
处理这些问题。可以使用其他集合,例如列表,但我发现使用映射的代码更容易阅读(并且可能不是性能问题,除非列表中有数百万个元素)
在这种情况下,我将有一个映射
,用于保持条目的正确顺序。这样的映射将作为值存储在另一个映射中,其中键是级别号。我将使用TreeMap
作为实现类,因为它根据条目的键对条目进行排序
Map<Integer,Map<Integer,String>> map = new TreeMap<>();
int level=0; //current level
for (String line:templines) {
if (line.startsWith("==level ")) {
level=Integer.valueOf(line.substring(7).replace("==","").trim());
if (map.get(level)==null) map.put(level,new TreeMap<>());
} else if (line.length>0) {
int pos = line.indexOf('.');
if (pos>0) {
int n = Integer.valueOf(line.substring(0,pos));
line=line.substring(pos+1);
map.get(level).put(n,line);
}
}
}
Map Map=newtreemap();
智力水平=0//当前水平
用于(字符串行:模板行){
if(line.startsWith(“==level”){
level=Integer.valueOf(line.substring(7).replace(“==”,”).trim());
if(map.get(level)==null)map.put(level,newtreemap());
}else if(行长度>0){
int pos=行索引('.');
如果(位置>0){
int n=整数.valueOf(行.子字符串(0,pos));
行=行子串(位置+1);
地图。获取(水平)。放置(n,线);
}
}
}
一旦我有了地图,我会迭代它并将值保存在另一个列表中
List<String> merged = new ArrayList<String>();
for (Map.Entry<Integer,Map<Integer,String>> entry:map.entrySet()) {
list.add("==level "+entry.getKey()+"==");
for (String line:entry.getValue().values()) {
list.add(line);
}
}
List merged=new ArrayList();
对于(Map.Entry:Map.entrySet()){
list.add(“==level”+entry.getKey()+“==”);
for(字符串行:entry.getValue().values()){
列表。添加(行);
}
}
基本上,您必须使用一个地图,将每个关卡作为键,并将一系列行作为值。处理完要合并的列表后,获取密钥集并对其进行降序排序,以便对级别进行排序。然后,可以使用排序的键/级别开始迭代贴图值。将级别添加到dest列表中,根据实际级别对列表进行排序,并将其所有元素也添加到dest中
以下是我的想法:
public class MergeLists {
private final static String[] list1 = {
"==level 1==\r\n",
"1.1 2\r\n",
"\r\n",
"\r\n",
"==level 2==\r\n",
"1.R4 0\r\n",
"2.0 2\r\n",
"\r\n",
"\r\n",
"==level 3==\r\n",
"3.R3 1\r\n",
"4.R5 1"
};
private final static String[] list2 = {
"==level 3==\r\n",
"1.null\r\n",
"2.null"
};
@Test
public void mergLists() {
List<List<String>> listList = new ArrayList<>();
listList.add(Arrays.asList(list1));
listList.add(Arrays.asList(list2));
List<String> mergedList = mergLists(listList);
for(String s : mergedList) {
System.out.println(s);
}
}
public List<String> mergLists(List<List<String>> listList) {
List<String> mergedList = new ArrayList<>();
Map<String, List<String>> levelMap = new HashMap<String, List<String>>();
for(int j = 0; j < listList.size(); j++) {
List<String> list = listList.get(j);
String actLevel = null;
for(int i = 0; i < list.size(); i++) {
String line = list.get(i).trim();
if(isLevel(line)) {
actLevel = line;
} else {
if(actLevel != null) {
List<String> levelList = levelMap.get(actLevel);
if(levelList == null) {
levelList = new ArrayList<>();
levelMap.put(actLevel, levelList);
}
levelList.add(line);
} else {
System.out.println("line " + (i+1) + " in list " + (j+1) + " does not belong to a level.");
}
}
}
}
List<String> sortedLevelList = new ArrayList<>(levelMap.keySet());
Collections.sort(sortedLevelList, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return (extractNumberFromLevel(o1) - extractNumberFromLevel(o2));
}
private int extractNumberFromLevel(String level) {
// check that this meets the format of your level entry (assuming "==level n==")
int r = 0;
int i = level.indexOf("level");
if(i != -1) {
int j = level.lastIndexOf("==");
if(j != -1) {
String n = level.substring(i + "level".length(), j).trim();
try {
r = Integer.parseInt(n);
} catch(NumberFormatException e) {
// ignore and return 0
}
}
}
return r;
}
});
for(String level : sortedLevelList) {
List<String> lineList = levelMap.get(level);
Collections.sort(lineList, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.trim().length() == 0 ? 1 /* this puts the empty string at the end of the list */
: (extractNumberFromLine(o1) - extractNumberFromLine(o2));
}
private int extractNumberFromLine(String o) {
// check that this meets the format of your line entry (assuming "n.1 2")
int r = 0;
int i = o.indexOf('.');
if(i != -1) {
String n = o.substring(0, i).trim();
try {
r = Integer.parseInt(n);
} catch(NumberFormatException e) {
// ignore and return 0
}
}
return r;
}
});
mergedList.add(level);
mergedList.addAll(lineList);
}
return mergedList;
}
private boolean isLevel(String line) {
// check that this meets the format of your level entry (assuming "==level n==")
return line.contains("level");
}
}
基本上,你必须使用一个地图,把每一个关卡作为键,把一系列的线作为值。处理完要合并的列表后,获取密钥集并对其进行降序排序,以便对级别进行排序。然后,可以使用排序的键/级别开始迭代贴图值。将级别添加到dest列表中,根据实际级别对列表进行排序,并将其所有元素也添加到dest中 以下是我的想法:
public class MergeLists {
private final static String[] list1 = {
"==level 1==\r\n",
"1.1 2\r\n",
"\r\n",
"\r\n",
"==level 2==\r\n",
"1.R4 0\r\n",
"2.0 2\r\n",
"\r\n",
"\r\n",
"==level 3==\r\n",
"3.R3 1\r\n",
"4.R5 1"
};
private final static String[] list2 = {
"==level 3==\r\n",
"1.null\r\n",
"2.null"
};
@Test
public void mergLists() {
List<List<String>> listList = new ArrayList<>();
listList.add(Arrays.asList(list1));
listList.add(Arrays.asList(list2));
List<String> mergedList = mergLists(listList);
for(String s : mergedList) {
System.out.println(s);
}
}
public List<String> mergLists(List<List<String>> listList) {
List<String> mergedList = new ArrayList<>();
Map<String, List<String>> levelMap = new HashMap<String, List<String>>();
for(int j = 0; j < listList.size(); j++) {
List<String> list = listList.get(j);
String actLevel = null;
for(int i = 0; i < list.size(); i++) {
String line = list.get(i).trim();
if(isLevel(line)) {
actLevel = line;
} else {
if(actLevel != null) {
List<String> levelList = levelMap.get(actLevel);
if(levelList == null) {
levelList = new ArrayList<>();
levelMap.put(actLevel, levelList);
}
levelList.add(line);
} else {
System.out.println("line " + (i+1) + " in list " + (j+1) + " does not belong to a level.");
}
}
}
}
List<String> sortedLevelList = new ArrayList<>(levelMap.keySet());
Collections.sort(sortedLevelList, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return (extractNumberFromLevel(o1) - extractNumberFromLevel(o2));
}
private int extractNumberFromLevel(String level) {
// check that this meets the format of your level entry (assuming "==level n==")
int r = 0;
int i = level.indexOf("level");
if(i != -1) {
int j = level.lastIndexOf("==");
if(j != -1) {
String n = level.substring(i + "level".length(), j).trim();
try {
r = Integer.parseInt(n);
} catch(NumberFormatException e) {
// ignore and return 0
}
}
}
return r;
}
});
for(String level : sortedLevelList) {
List<String> lineList = levelMap.get(level);
Collections.sort(lineList, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.trim().length() == 0 ? 1 /* this puts the empty string at the end of the list */
: (extractNumberFromLine(o1) - extractNumberFromLine(o2));
}
private int extractNumberFromLine(String o) {
// check that this meets the format of your line entry (assuming "n.1 2")
int r = 0;
int i = o.indexOf('.');
if(i != -1) {
String n = o.substring(0, i).trim();
try {
r = Integer.parseInt(n);
} catch(NumberFormatException e) {
// ignore and return 0
}
}
return r;
}
});
mergedList.add(level);
mergedList.addAll(lineList);
}
return mergedList;
}
private boolean isLevel(String line) {
// check that this meets the format of your level entry (assuming "==level n==")
return line.contains("level");
}
}
假设您的两个输入列表都是按升序排序的,您可以使用合并两个已排序列表/数组的标准方法。主要的一点是,在算法中不需要嵌套循环,而是交替地遍历两个列表,始终将较低的元素附加到结果中,并在该列表中前进。这是一张关于数字和等级区别的草图
int ix_a = 0;
int ix_b = 0;
List<String> result = new ArrayList<String>();
while (ix_a < A.size() || ix_b < B.size()) {
// No more elements in A => append everything from B to result
if (ix_a == A.size()) {
result.add(B.get(ix_b));
ix_b++;
continue;
}
// No more elements in B => append everything from A to result
if (ix_b == B.size()) {
result.add(A.get(ix_a));
ix_a++;
continue;
}
// Always append the lower element and advance in that list.
// If both lists contain the same element, append this once and advance in both lists
// Distinguish between levels and numbers here, levels take higher precedence.
String a = A.get(ix_a);
String b = B.get(ix_b);
if (isLevel(a) && isLevel(b)) {
if (isLowerLevel(a, b)) {
result.add(a);
ix_a++;
} else if (isLowerLevel(b, a)) {
result.add(b);
ix_b++;
} else {
result.add(a);
ix_a++;
ix_b++;
}
} else if (isLevel(a)) {
result.add(b);
ix_b++;
} else if (isLevel(b)) {
result.add(a);
ix_a++;
} else {
if (isLowerNumber(a, b)) {
result.add(a);
ix_a++;
} else if (isLowerNumber(b, a)) {
result.add(b);
ix_b++;
} else {
result.add(a);
ix_a++;
ix_b++;
}
}
}
intix_a=0;
int ix_b=0;
列表结果=新建ArrayList();
而(ix_a中不再有元素将从B到result的所有内容追加
如果(ix_a==a.size()){
结果。添加(B。