【问题标题】:Issue with updating multiple values with the same key using HashMap使用 HashMap 更新具有相同键的多个值的问题
【发布时间】:2016-11-10 19:16:03
【问题描述】:

我遇到了一个问题,即一个键/值对正在正确更新,但具有相同键的其他值没有得到更新。我正在使用一个 HashMap,它由一个字符串列表(项目 Nbr)作为键和存储为字符串列表(PO Nbr)的值组成,因此在这方面它本质上是一对多的。下面是我实现这个 HashMap 的代码,但我只是卡住了。任何帮助将不胜感激。

public void process(List<PoBean> excelData,List<String> errors) throws CustomException 
{       
    Map<String,ArrayList<String>> poNbrItemNbrMap = new HashMap<String, ArrayList<String>>();
    ArrayList<String> poNbrList = new ArrayList<String>();

    int recordCount = excelData.size();

    for(PoBean bean : excelData)
    {                                       
        if(rowValidator.validate(bean, errors))
        {
            if (!newErrorInRow(errors)) 
            {
                poNbrList.add(bean.getPoId());
                poNbrItemNbrMap.put(bean.getItemNbr(),bean.getPoId());
            }           
        }
    }

    List<DutyFees> dutyFeesTempDAO = myService.getAssocIdByPOAndItemNbr(new ArrayList<String>(poNbrItemNbrMap.keySet()),new ArrayList<String>(poNbrItemNbrMap.values()));           

    for(DutyFees duty : dutyFeesTempDAO)
    {   
        Double dutyFees = new Double(0);
        if(poNbrItemNbrMap.containsKey(duty.getItemNbr()) && poNbrItemNbrMap.containsValue(duty.getPoId())) 
        {               
            for(PoBean dutyBean : excelData)
            {
                if(duty.getPoId().equals(dutyBean.getPoId()) && duty.getItemNbr().equals(dutyBean.getItemNbr()))
                {
                    dutyFees = new Double(dutyBean.getDutyFees());
                    break;
                }
            }
            Boolean result = myService.updateDutyFeesByAssocID(duty.getAssocId(), dutyFees);            
        }                               
    }       
}

【问题讨论】:

  • "具有相同键的其他值没有得到更新" -- HashMap 中不能有具有相同键的其他值。
  • 如果你有一对多的关系,你需要一个Map&lt;String, List&lt;String&gt;&gt;
  • 或来自某个第 3 方库的 MultiMap

标签: java hashmap key-value


【解决方案1】:

你说你想要一对多,但你的代码是一对一的

HashMap<String,String> poNbrItemNbrMap = new HashMap<String,String>();

一个字符串键对应一个字符串值

斜体部分与您的问题中的粗体部分形成对比。

我正在使用由字符串列表(项目 Nbr)组成的 HashMap 作为 存储为字符串列表 (PO Nbr) 的键和值, 所以它是 在这方面基本上是一对多。

斜体表示多对多。 粗体表示一对多。

无论如何,让我给你两个实现。

public class Test {
  public static void main(String[] args) {

    System.out.println("= One to Many =");
    Map<String, List<String>> stringListMap = new HashMap<>();
    String key = "list of 4 strings";
    List<String> valuesList = Arrays.asList("one","two","three","four");
    stringListMap.put(key,valuesList);
    stringListMap.forEach((strings, strings2) -> System.out.println(strings.toString() + strings2.toString()));

    System.out.println("= Many to Many =");
    Map<List<String>, List<String>> listListMap = new HashMap<>();
    List<String> keys = Arrays.asList("1","2","3","4");
    List<String> values = Arrays.asList("one","two","three","four");
    listListMap.put(keys,values);
    listListMap.forEach((strings, strings2) -> System.out.println(strings.toString() + strings2.toString()));


  }
}

EDIT 回复您的评论。 不确定您在那条评论中的意思,但我确实看到了几个问题。首先,当您输入地图时,您输入的内容似乎是项目编号和 po id,因此它们似乎都是单个字符串类型而不是 ArrayList 类型。所以我什至不确定你如何编译它。除非您的 getPoId 实际上是 getPoIds 并返回一个列表。我说的是这条线

poNbrItemNbrMap.put(bean.getItemNbr(),bean.getPoId());

现在关于

new ArrayList<String>(poNbrItemNbrMap.values())

你不能这样初始化数组列表。

我不知道 getAssocIdByPoAndItemNbr 函数的签名是什么,所以无法给出答案。但是,如果您只想发送映射值,那么直接发送它,为什么将其作为构造函数参数放入 new ArrayList()?

【讨论】:

  • 我现在明白我做错了什么,但现在每当我这样做时,它都会要求我将我的 bean 类中 getPoId() 的返回类型更改为 List 所以它不会只是这样做是行不通的。我不确定如何将该 bean 的值存储到列表中。我会在我的迭代器中这样做吗?我已经设置了通过 excelData?在这一点上,我有点迷茫和困惑。
  • List 是一种抽象类型,因此您需要初始化列表的具体实现,例如ArrayList。因此,您将其初始化为 List&lt;String&gt; listOfStrings = new ArrayList&lt;&gt;; 这将初始化一个字符串列表。如果要存储/创建 bean 列表,可以将泛型更改为 PoBean。稍后您可以通过调用 listOfStrings.add("hello"); 为其添加值
  • 所以现在我在使用泛型和 >) 后遇到了问题。我初始化了一个 ArrayList 对象并在我的 !newErrorsInRows(errors) 检查中说 poNbrList.add(bean.getPOId());...现在,我有代码 new ArrayList(poNbrItemNbrMap.values () 作为 getAssocIdByPOAndItemNbr 的输入参数,它表示要更改为 ArrayList,但这对接受所有输入的值没有任何作用。我的常量文件中的该方法表明它期望 (List, List). 我卡住了
  • 仅供参考我更新了原始帖子中的代码以反映在 if (!newErrorsInRows(errors) 中使用 Map> 并执行 poNbrList.add(bean.getPoId()) ) 检查
【解决方案2】:

process 的第一部分的目的很明确:将PoBean 对象列表转换为Map&lt;String, List&lt;String&gt;&gt;,将对象按itemNbr 分组为一个列表。这是执行此操作的代码:

// One-to-many relationship requires the value to be a List
// Better not say ArrayList here because then you put unnecessary
// Restrictions on the code.
Map<String, List<String>> poNbrItemNbrMap = new HashMap<>();

for(PoBean bean : excelData)
{                                       
    if(rowValidator.validate(bean, errors))
    {
        if (!newErrorInRow(errors)) 
        {
            String key = bean.getItemNbr();
            List<String> value = poNbrItemNbrMap.get(key);
            if (value == null) {
                // This is first time we see this item nbr,
                // Create a new list to hold the values
                value = new ArrayList<>();
                poNbrItemNbrMap.put(key, value);
            }
            // Just add the value to the list
            value.add(bean.getPoId());
        }           
    }
}

现在第二部分令人困惑,尤其是这一行:

List<DutyFees> dutyFeesTempDAO = myService.getAssocIdByPOAndItemNbr(new ArrayList<String>(poNbrItemNbrMap.keySet()),new ArrayList<String>(poNbrItemNbrMap.values()));

第一个参数几乎没有意义,它以List 的形式传递键;没关系。第二个参数无法编译,因为您需要new ArrayList&lt;List&lt;String&gt;&gt;(poNbrItemNbrMap.values())。是的,您需要一个字符串列表。但这仅仅是开始。 这样你就基本消除了键和值之间的关系,getAssocIdByPOAndItemNbr 方法不能再关联键和它们各自的值了。它不能假设键中的第一项映射到值中的第一项。这意味着我们在第一部分所做的任何事情都是无用的。

【讨论】:

  • 因此,如果我想将一个键与字符串列表相关联,最好将一组键与字符串列表的集合相关联,这怎么会发生呢? getAssocIdByPOAndItemNbr 方法需要一个 List,List,我可以将其更改为需要一个 Set keySet, Collection> 值,但这也会禁用将键关联到它们各自的能力价值观?
  • 为什么不直接传入我们刚刚创建的地图?
猜你喜欢
  • 2014-08-18
  • 2013-10-16
  • 2012-05-17
  • 1970-01-01
  • 1970-01-01
  • 2015-11-22
  • 2013-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多