二维映射Java

二维映射Java,java,matrix,hashmap,Java,Matrix,Hashmap,我需要一个可以以二维方式存储信息的数据结构。例如,想象一个包含用户项目评级的表。我需要存储所有用户的所有评分。比方说,用户u1。我需要存储用户u1、u2和u3以及所有其他用户的评级。但问题是我还需要存储所有项目的所有评分。例如,我需要存储所有用户为每个项目提供的评分。所以我需要一个类似于地图的东西,对于用户来说,关键是用户ID,值是评级集。我很容易做到。但我的问题是如何存储物品的评级。例如,一个映射,其键是项目ID,值是用户为该项目提供的评分集。我想上传一个表,但因为我没有足够的声誉,所以我无法

我需要一个可以以二维方式存储信息的数据结构。例如,想象一个包含用户项目评级的表。我需要存储所有用户的所有评分。比方说,用户u1。我需要存储用户u1、u2和u3以及所有其他用户的评级。但问题是我还需要存储所有项目的所有评分。例如,我需要存储所有用户为每个项目提供的评分。所以我需要一个类似于地图的东西,对于用户来说,关键是用户ID,值是评级集。我很容易做到。但我的问题是如何存储物品的评级。例如,一个映射,其键是项目ID,值是用户为该项目提供的评分集。我想上传一个表,但因为我没有足够的声誉,所以我无法上传。所以想象一下,一个像二维矩阵一样的表,行是用户,列是项目。是否有一个数据结构可以做到这一点?或者我应该建立两个不同的地图?也许有一个比地图更好的选择,但因为我必须为我的问题选择一个标题,所以我写了地图


谢谢

所以,你有两个一个多的关系。一个用户有(给出)很多评分,一个项目有很多评分;这就产生了许多用户之间的关系,而这正是您的问题所在。为什么不简单地按照以下描述对其进行建模:

public class Rating {
  private User ratedBy;
  private Item itemRated;

  public Item getItem() { return itemRated; }
}

public class User {
  private Set<Rating> allRatings = new HashSet<>();

  public Rating getRatingFor(Item item) {
      for(Rating rating: allRatings) {
          if(item.equals(rating.getItem()) {
              return rating;
          }
      }
      return null;
  }
}

public class Item {
  private Set<Rating> allRatings = new HashSet<>();
}

一个快速而肮脏的解决方案是使用二维键。 假设用户和项的id都是相同类型的,您可以创建一个类,该类只是id和密钥类型的持有者。(如果可用,类型可以是用户或项的类,也可以是枚举值)。然后使地图具有此类型的键。当然,每个等级至少会被引用两次(每种类型一次)

您可以使用免费库中的类

Table Table=HashBasedTable.create();
表.put(1,“a”,2.0);
双v=表。获取(1,“a”);//获得2.0

您需要的数据结构称为表。一个表有两个键和一个对象,看起来或多或少像一个excel表,有两个键集作为列和行。因此得名。有各种各样的表实现。我认为现在使用番石榴是正常的。这里有一个解释


guava表的API,以及您想要的实现,HashBasedTable,

这里是我自己版本的适当表对象。请注意,使用现有库提供的东西是很好的。但是尝试自己的实现将帮助您更好地理解所涉及的问题。因此,您可以尝试将“删除”方法等添加到我的实现中以完成它

我更喜欢将数据保存在表中,而不是在
User
Item
中实现映射,因为表可以强制通过行和列添加每个新评级。如果将贴图分别放在两个独立的对象中,则无法强制执行此操作

请注意,虽然我在
getCol
getRow
中返回内部映射的保护副本,但我返回的是实际值的引用,而不是其副本,因此您可以更改用户的评级(假设您为此选择了可变对象),而无需更改表结构。还要注意的是,如果用户和项目对象是可变的,并且这会影响它们的
equals
hashCode
,则该表的行为将不可预测

public class Table<K1, K2, V> {

    // Two maps allowing us to retrieve the value through the row or the
    // column key.
    private Map<K1, Map<K2, V>> rowMap;
    private Map<K2, Map<K1, V>> colMap;

    public Table() {
        rowMap = new HashMap<>();
        colMap = new HashMap<>();
    }

    /**
     * Allows us to create a key for the row, and place it in the structure
     * while there are still no relations for it.
     *
     * @param key
     *            The key for which a new empty row will be created.
     */
    public void addEmptyRow(K1 key) {
        if (!rowMap.containsKey(key)) {
            rowMap.put(key, new HashMap<K2, V>());
        }
    }

    /**
     * Allows us to create a key for the column, and place it in the
     * structure while there are still no relations for it.
     * 
     * @param key
     *            The key for which a new empty column will be created.
     */
    public void addEmptyCol(K2 key) {
        if (!colMap.containsKey(key)) {
            colMap.put(key, new HashMap<K1, V>());
        }
    }

    /**
     * Insert a value into the table using the two keys.
     * 
     * @param rowKey
     *            Row key to access this value
     * @param colKey
     *            Column key to access this value
     * @param value
     *            The value to be associated with the above two keys.
     */
    public void put(K1 rowKey, K2 colKey, V value) {
        Map<K2, V> row;
        Map<K1, V> col;

        // Find the internal row. If there is no entry, create one.
        if (rowMap.containsKey(rowKey)) {
            row = rowMap.get(rowKey);
        } else {
            row = new HashMap<K2, V>();
            rowMap.put(rowKey, row);
        }

        // Find the internal column, If there is no entry, create one.
        if (colMap.containsKey(colKey)) {
            col = colMap.get(colKey);
        } else {
            col = new HashMap<K1, V>();
            colMap.put(colKey, col);
        }

        // Add the value to both row and column.
        row.put(colKey, value);
        col.put(rowKey, value);
    }

    /**
     * Get the value associated with the given row and column.
     * 
     * @param rowKey
     *            Row key to access the value
     * @param colKey
     *            Column key to access the value
     * @return Value in the given row and column. Null if mapping doesn't
     *         exist
     */

    public V get(K1 rowKey, K2 colKey) {
        Map<K2, V> row;
        row = rowMap.get(rowKey);
        if (row != null) {
            return row.get(colKey);
        }
        return null;
    }

    /**
     * Get a map representing the row for the given key. The map contains
     * only column keys that actually have values in this row.
     * 
     * @param rowKey
     *            The key to the row in the table
     * @return Map representing the row. Null if there is no row with the
     *         given key.
     */
    public Map<K2, V> getRow(K1 rowKey) {
        // Note that we are returning a protective copy of the row. The user
        // cannot change the internal structure of the table, but is allowed
        // to change the value's state if it is mutable.
        if (rowMap.containsKey(rowKey)) {
            return new HashMap<>(rowMap.get(rowKey));
        }
        return null;
    }

    /**
     * Get a map representing the column for the given key. The map contains
     * only row keys that actually have values in this column.
     * 
     * @param colKey
     *            The key to the column in the table.
     * @return Map representing the column. Null if there is no column with
     *         the given key.
     */
    public Map<K1, V> getCol(K2 colKey) {
        // Note that we are returning a protective copy of the column. The
        // user cannot change the internal structure.
        if (colMap.containsKey(colKey)) {
            return new HashMap<>(colMap.get(colKey));
        }
        return null;
    }

    /**
     * Get a set of all the existing row keys.
     * 
     * @return A Set containing all the row keys. The set may be empty.
     */
    public Set<K1> getRowKeys() {
        return new HashSet(rowMap.keySet());
    }

    /**
     * Get a set of all the existing column keys.
     * 
     * @return A set containing all the column keys. The set may be empty.
     */
    public Set<K2> getColKeys() {
        return new HashSet(colMap.keySet());
    }
}
然后为特定用户查询表,如下所示:

    Map<Item, Rating> anakinsRatings = table.getRow(user);

    for (Map.Entry<Item, Rating> entry : anakinsRatings.entrySet()) {
        System.out.println(user + " rated " + entry.getKey() + " as "
                + entry.getValue().getRating());
    }
Map anakinsrattings=table.getRow(用户);
for(Map.Entry:anakinsRatings.entrySet()){
System.out.println(用户+“额定值”+entry.getKey()+“作为”
+entry.getValue().getRating());
}
或显示所有项目的评级列表,如:

    for (Item currItem : table.getColKeys()) {
        Map<User, Rating> itemMap = table.getCol(currItem);
        if (itemMap.isEmpty()) {
            System.out.println("There are currently no ratings for \""
                    + currItem
                    + "\"");
        } else {
            for (Map.Entry<User, Rating> entry : table.getCol(currItem).entrySet()) {
                System.out.println("\""
                        + currItem
                        + "\" has been rated "
                        + entry.getValue().getRating() + " by "
                        + entry.getKey());
            }
        }
    }
for(项curroitem:table.getColKeys()){
Map itemMap=table.getCol(curroitem);
if(itemMap.isEmpty()){
System.out.println(“当前没有针对\”的评级”
+货币项目
+ "\"");
}否则{
for(Map.Entry:table.getCol(currItem.entrySet()){
System.out.println(“\”)
+货币项目
+“\”已被评级”
+entry.getValue().getRating()+“by”
+entry.getKey());
}
}
}

正如我所说的,实现还没有完成-表中没有
toString
,例如,没有
remove
removeow
removeCol
clear
,等等。

我认为多对多数据库关系可以解决这个问题。为什么需要将其直接实现到java中呢?我可以提供一些例子,也许是:@TomasSmagurauskas,因为我需要使用java对这些数据进行一些数据分析,谢谢。为什么要为用户和项目使用类?看来这门课只是一套。那么,为什么不在评级计算中定义这些集合呢?
    Table<User, Item, Rating> table = new Table<>();

    table.addEmptyCol(new Item("Television"));
    table.addEmptyCol(new Item("Sofa"));

    User user = new User("Anakin");
    Item item = new Item("Light Sabre");
    table.put(user, item, new Rating(5));

    Item item1 = new Item("Helmet");
    table.put(user, item1, new Rating(7));

    Rating rating = table.get(user, item);
    rating.setRating(rating.getRating() + 10);

    User user1 = new User("Obi-Wan");
    table.put(user1, item, new Rating(8));
    table.put(user1, new Item("Television"), new Rating(0));
    Map<Item, Rating> anakinsRatings = table.getRow(user);

    for (Map.Entry<Item, Rating> entry : anakinsRatings.entrySet()) {
        System.out.println(user + " rated " + entry.getKey() + " as "
                + entry.getValue().getRating());
    }
    for (Item currItem : table.getColKeys()) {
        Map<User, Rating> itemMap = table.getCol(currItem);
        if (itemMap.isEmpty()) {
            System.out.println("There are currently no ratings for \""
                    + currItem
                    + "\"");
        } else {
            for (Map.Entry<User, Rating> entry : table.getCol(currItem).entrySet()) {
                System.out.println("\""
                        + currItem
                        + "\" has been rated "
                        + entry.getValue().getRating() + " by "
                        + entry.getKey());
            }
        }
    }