如何比较两个哈希映射<字符串,列表<String>>



我想比较从excel文件读取的数据(键是列1,值是列2),正放入HashMap与从SQL查询获得的数据。一开始我使用HashMap<String,>因为我只需要比较<键值>对,但现在我要比较<键,列表,我有点卡住了。下面是我读取xls文件的代码:>

public class ReadExcel {
    HashMap<String, List<String>> result = new HashMap<String, List<String>>();
public HashMap<String, List<String>> process() {
    try
    {
        result.clear();
        FileInputStream file = new FileInputStream(new File("C:/some.xlsx"));
        //Create Workbook instance holding reference to .xlsx file
        XSSFWorkbook workbook = new XSSFWorkbook(file);
        //Get first/desired sheet from the workbook
        XSSFSheet sheet = workbook.getSheetAt(0);
        //Iterate through each rows one by one
        Iterator<Row> rowIterator = sheet.iterator();

        while (rowIterator.hasNext()) {
            List<String> xlsList = new ArrayList<String>();
                Row row = rowIterator.next();
                Cell cell  = row.getCell(1);
                Cell cell2 = row.getCell(2);
                String key ="";
                String value="";
                xlsList.clear();
                switch (cell.getCellType())
                {
                    case Cell.CELL_TYPE_NUMERIC:
                        key = getStringCellValue(cell);
                        value = getNumericCellValue(cell2);
                        break;
                    case Cell.CELL_TYPE_STRING:
                        key = getStringCellValue(cell);
                        value = getStringCellValue(cell2);
                        break;
                }
                xlsList.add(value);
                result.put(key, xlsList);
        }
    }
}

例如在我的excel文件中

row 1: column 1 = car, column 2 = blue
row 2: column 1 = car, column 2 = yellow.

当我运行excel阅读器时,它将值"蓝色,黄色"放在HashMap中的"汽车"键下非常好。当我有例如:

row 1: column 1 = car,  column 2 = blue
row 2: column 1 = car,  column 2 = yellow
row 3: column 1 = year, column 2 = 1990
row 4: column 1 = year, column 2 = 1999

只显示:car=[yellow], year=[1999]。它只接受最后一个值,如果没有重复的键,这工作得很好。

第一个问题:我怎样才能做得更好?如果我在第一行有相同的键只取一次键并存储第二行的所有值如果第一行的键是相同的?

下面是我从SQL数据库中提取数据的代码:

public class DB {
    HashMap<String, List<String>> result = new HashMap<String, List<String>>();
public HashMap<String, List<String>> process() {
    result.clear();
    Connection conn = null;
    Statement stmt = null;
    List<String> carColour = new ArrayList<String>();
try {
        Class.forName("oracle.jdbc.driver.OracleDriver");
        conn = DriverManager.getConnection(DB_URL, USER, PASS);
        stmt = conn.createStatement();
        String sql1 = "SOME SQL SELECT STATEMENT THAT RETURNS 2 or more lines, by that i mean "car" has 2 values or more";
        ResultSet rs = stmt.executeQuery(sql1);
        while(rs.next()){
            carColour.add(rs.getString("colour")); // i select the column "colour"
            result.put("car", carColour);         // i put "car" as key, and "blue" and "yellow" as values
            ...................................
        }
} catch...
}

这段代码的DB工作正常,但如果我想提取更多的列,如"颜色"或"年",我必须为所有他们创建列表,如果我有像20列提取,它可能是非常耗时的。

第二个问题:比起创建20个列表,我如何才能更容易地做到这一点?(使用相同的list maybe和list.clear();(这里取决于,因为如果我有30列,我只需要20,我可以getString("列")所有,并删除那些我不想要的,但如何?

下面是比较代码:

final Map<String, Boolean> comparisonResult = compareEntries(dbResult, xlsResult);
        for(final Entry<String, Boolean> entry : comparisonResult.entrySet()){
            if (entry.getValue() == false){
                System.out.println("------------------------------------------------------------------------");
                System.out.println("| Comparison FAILED | Value not matching! Column name --> " + entry.getKey() + " |");
            }
        }
        System.out.println("------------------------------------------------------------------------");
        System.out.println("DB consistency check finished.");

................................................................................

public static <K extends Comparable<? super K>, V>
Map<K, Boolean> compareEntries(final Map<K, V> dbResult,
    final Map<K, V> xlsResult){
    final Collection<K> allKeys = new HashSet<K>();
    allKeys.addAll(dbResult.keySet());
    allKeys.addAll(xlsResult.keySet());
    final Map<K, Boolean> result = new TreeMap<K, Boolean>();
    for(final K key : allKeys){
        result.put(key, dbResult.containsKey(key) == xlsResult.containsKey(key) && Boolean.valueOf(equal(dbResult.get(key), xlsResult.get(key))));
    }
    return result;
}
private static boolean equal(final Object obj1, final Object obj2){
    return obj1 == obj2 || (obj1 != null && obj1.equals(obj2));
}

最后一个问题:我如何改进代码来比较两个HashMap(String, List<字符串>),或者我如何一步一步更好地做到这一点?谢谢你!

你的ReadExcel读取循环有一个严重的问题:而不是重用List,这已经被一个键映射,你总是创建一个新的,因此你最终会有一个只有一个(最后一个)值的列表。

下面是修复这个问题的方法(使用Java 8):

// ...
while (rowIterator.hasNext()) {
    Row row = rowIterator.next();
    Cell keyCell = row.getCell(1);
    Cell valCell = row.getCell(2);
    String key = getStringCellValue(keyCell);
    switch (cell.getCellType()) {
        case Cell.CELL_TYPE_NUMERIC:
            value = getNumericCellValue(valCell);
            break;
        case Cell.CELL_TYPE_STRING:
            value = getStringCellValue(valCell);
            break;
        }
    }
    // this line only compiles since Java 8
    result.computeIfAbsent(key, k -> new HashSet<Object>()).add(value);
}

如果您还没有使用Java 8,请快速下载,或者将上面的最后一行替换为:

Set<Object> list = result.get(key);
if (list == null) result.put(key, list = new HashSet<Object>());
list.add(value);

比较Map对象相当容易-您可以直接使用equals比较它们:

if (map1.equals(map2)) {
    // both maps are equal!
} else {
    // maps are NOT equal!
}

当然,这只产生truefalse。如果您想知道细节(哪些条目不同),您需要自己做。

最新更新