【问题标题】:Create a 2d Boolean array in Java from table data在 Java 中从表数据创建一个二维布尔数组
【发布时间】:2025-11-28 18:30:01
【问题描述】:

我有一个 .csv 文件类型:

Event                     Participant  
ConferenceA               John   
ConferenceA               Joe  
ConferenceA               Mary    
ConferenceB               John  
ConferenceB               Ted  
ConferenceC               Jessica  

我想创建一个以下格式的二维布尔矩阵:

Event        John  Joe  Mary  Ted  Jessica  
ConferenceA  1     1    1     0    0  
ConferenceB  1     0    0     1    0  
ConferenceC  0     0    0     0    1  

我首先读取 csv 并使用它来初始化一个 ArrayList 类型:

AttendaceRecord(String title, String employee)

我如何遍历这个 ArrayList 来创建一个类似于上面 Java 中的布尔矩阵?

【问题讨论】:

  • 这个 CSV 可以有任意数量的会议和/或参与者?
  • 在将其插入 ArrayList 时,您是否维护其他变量,例如您拥有多少不同的员工或事件?
  • 为什么不直接使用 Map 呢?关键是会议,价值是参与者?它必须是 ArrayList 吗?这对你来说会容易得多。
  • @SaviourSelf 虽然这可能是个好主意,但我并没有维护这些信息。最终,这些数据将来自一个数据库。我只是用 csv 进行原型设计
  • @Andy 它不一定是 ArrayList。我对地图的经验很少,但我对这种实施持开放态度

标签: java data-structures boolean multidimensional-array indicator


【解决方案1】:

这是我能想到的最简单的方法。这个答案当然可以改进或以完全不同的方式完成。我采用这种方法是因为您提到您对Map 并不完全熟悉(我也在猜测Set)。无论如何,让我们潜入。

在您的AttendanceRecord 类中,您将需要以下实例变量:两个LinkedHashSet 和一个LinkedHashMapLinkedHashSet #1 将存储所有会议,LinkedHashSet #2 将存储所有参与者。 LinkedHashMap 会将会议存储为keys,将参与者list 存储为values。原因将在一分钟内清楚。我将首先解释为什么您需要LinkedHashSet

LinkedHashSet 的用途

请注意,在您的二维数组中,行(会议)和列(参与者)按读取顺序排列。不仅如此,从文件中读取的所有重复项都消失了。为了保持顺序并消除重复,LinkedHashSet 非常适合这个目的。然后,我们将通过它们的数组表示在二维数组和每个LinkedHashSet 的行位置和列位置之间建立一对一的关系。例如,让我们使用来自ConferenceAJhonJhon 将位于与会者 Set 的数组表示中的位置 0,ConferenceA 将位于会议 Set 的数组表示中的位置 0。不仅如此,每个数组的大小都会用来决定你的二维数组的大小(2darray[conferenceArrayLength][participantArrayLength])

LinkedHashMap 的用途

我们需要LinkedHashMap 来保持元素的顺序(因此Linked)。元素将像这样在内部存储。

ConferenceA :Jhon Joe Mary 
ConferenceB :Jhon Ted 
ConferenceC :Jessica 

然后我们将遍历数据结构并将每个 key value 对发送到一个函数,该函数返回每个 LinkedHashSet 返回的每个数组中每个元素的位置。当返回每一行和每一列的位置时,我们将在二维数组中的该位置添加一个 1。

注意:我在示例中使用了整数数组,根据需要替换。

AttendanceRecord.java

public class AttendanceRecord {

    private Map<String, ArrayList> attendanceRecordMap = new LinkedHashMap<String, ArrayList>();
    private Set<String> participants = new LinkedHashSet<String>(); 
    private Set<String> conferences = new LinkedHashSet<String>(); 

    public AttendanceRecord() {
    }

    public Map<String, ArrayList> getAttendanceRecordMap() {
        return attendanceRecordMap;
    }

    public Object[] getParticipantsArray() {
        return participants.toArray();
    }

    public Object[] getConferencesArray() {

        return conferences.toArray();
    }

    public void addToRecord(String title, String employee) {

        conferences.add(title);
        participants.add(employee);

        if (attendanceRecordMap.containsKey(title)) {
            ArrayList<String> tempList = attendanceRecordMap.get(title);
            tempList.add(employee);
        } else {
            ArrayList<String> attendees = new ArrayList<String>();
            attendees.add(employee);
            attendanceRecordMap.put(title, attendees);
        }
    }
} 

Test.java

public class Test {

    public static void main(String[] args) {

        AttendanceRecord attendanceRecord = new AttendanceRecord();

        //There are hardcoded. You will have to substitute with your code 
        //when you read the file
        attendanceRecord.addToRecord("ConferenceA", "Jhon");
        attendanceRecord.addToRecord("ConferenceA", "Joe");
        attendanceRecord.addToRecord("ConferenceA", "Mary");
        attendanceRecord.addToRecord("ConferenceB", "Jhon");
        attendanceRecord.addToRecord("ConferenceB", "Ted");
        attendanceRecord.addToRecord("ConferenceC", "Jessica");

        int[][] jaccardArray = new int[attendanceRecord.getConferencesArray().length][attendanceRecord.getParticipantsArray().length];
        setUp2dArray(jaccardArray, attendanceRecord);
        print2dArray(jaccardArray);
    }

    public static void setUp2dArray(int[][] jaccardArray, AttendanceRecord record) {
        Map<String, ArrayList> recordMap = record.getAttendanceRecordMap();

        for (String key : recordMap.keySet()) {
            ArrayList<String> attendees = recordMap.get(key);

            for (String attendee : attendees) {
                int row = findConferencePosition(key, record.getConferencesArray());
                int column = findParticipantPosition(attendee, record.getParticipantsArray());
                System.out.println("Row inside " + row + "Col inside " + column);
                jaccardArray[row][column] = 1;
            }
        }
    }

    public static void print2dArray(int[][] jaccardArray) {
        for (int i = 0; i < jaccardArray.length; i++) {
            for (int j = 0; j < jaccardArray[i].length; j++) {
                System.out.print(jaccardArray[i][j]);
            }
            System.out.println();
        }
    }

    public static int findParticipantPosition(String employee, Object[] participantArray) {
        int position = -1;

        for (int i = 0; i < participantArray.length; i++) {
            if (employee.equals(participantArray[i].toString())) {
                position = i;
                break;
            }
        }
        return position;
    }

    public static int findConferencePosition(String employee, Object[] conferenceArray) {
        int position = -1;

        for (int i = 0; i < conferenceArray.length; i++) {
            if (employee.equals(conferenceArray[i])) {
                position = i;
                break;
            }
        }
        return position;
    }
}

【讨论】:

  • 对于“地图”和“设置”新手的精彩解释和演示!我确信其他解释也可以,但这是一个非常清晰且解释清楚的实现。谢谢
  • 不客气。很抱歉给出完整的答案(不过我认为你不介意)。我非常喜欢这个问题,我被带走了。祝你好运:)
【解决方案2】:

基本上,您首先要搜索输入字符串以查找每个名称 (String.contains) 并为每个字段名称设置一个布尔数组。

然后,您将创建一个由这些布尔数组组成的数组(或一个列表,等等)。

然后您只需对它们进行排序,查找 T/F 并打印相应的消息。

我包含了一些非常粗略的伪代码,假设我正确理解了您的问题。

// For first row
List labelStrings[];

labelStrings = {"Event", "John", "Joe", "Mary", "Ted", "Jessica"};

// For the matrix data

// List to iterate horizontally EDIT: Made boolean!
List<Boolean> strList= new ArrayList()<List>;
// List to iterate vertically
List<List> = listList new ArrayList()<List>;

/* for all the entries in AttendanceRecord (watch your spelling, OP)
   for all data sets mapping title to employee
       add the row data to strList[entry_num]  */

for (int i = 0; i < listList.size()-1; i++)
   for (int j = 0; j < labelStrings.size()-1; j++)
   {
      if (i == 0)
         System.out.println(strList[j] + "\t\n\n");
      else
      {
        // print listLists[i][j]
      }
    // iterate row by row (for each horizontal entry in the column of entries)
   }

抱歉,我现在只是在阅读 cmets。

您肯定希望以易于迭代的方式排列数据。由于您有一个固定的表大小,您可以为每个条目硬编码一个布尔数组,然后在验证时打印它们已映射到输入字符串中指示的事件。

【讨论】:

  • 我不认为表格大小是固定的。这就是为什么我要求他确定。再说一次,我从他的帖子中不清楚。
  • 无论哪种方式都不是硬性修复。我的目的是向 OP 提供有用的信息,以帮助他走上正轨。对于有多少回复,这个帖子总体上令人惊讶地缺乏投票。
  • 我知道,我不是在批评。
  • @jdero 随着更多活动和出席人数的增加,此桌子的大小会随着时间而变化
  • 那么就使用ArrayList。您可以随着列表的增长等调整输出。
【解决方案3】:

尝试创建一个包含

的哈希映射
HashMap map = new HashMap<conferenceStr, HashMap<nameStr, int>>()

当您遍历 ArrayList 时,您可以执行类似的操作

innerMap = map.get(conferenceStr)
innerMap.put(nameStr, 1)

当然你需要一些初始化逻辑,比如你可以检查 innerMap.get(nameStr) 是否存在,如果不存在,遍历每个内部映射和 innerMap.put(nameStr, 0)

此结构可用于生成最终的 2D 布尔矩阵。

细化编辑:

ArrayList<AttendanceRecord> attendanceList = new ArrayList<AttendanceRecord>();

// populate list with info from the csv (you implied you can do this)

HashMap<String, HashMap<String, Integer>> map = new HashMap<String, HashMap<String, Integer>>();

//map to store every participant, this seems inefficient though 
HashMap<String, Integer>> participantMap = new HashMap<String, Integer>();

for (AttendanceRecord record : attendanceList) {
  String title = record.getTitle();
  String employee = record.getEmployee();

  participantMap.put(employee, 0);


  HashMap<String, Integer> innerMap = map.get(title);
  if (innerMap == null) {
    innerMap = new HashMap<String, Integer>();

  }
  innerMap.put(employee, 1);
}

//now we have all the data we need, it's just about how you want to format it

例如,如果您只想打印出这样的表格,则可以这样做遍历 map 的每个元素:

for (HashMap<String, Integer> innerMap : map.values()) {
  for (String employee : participantMap.values()) {

    if (innerMap.get(employee)) {
      //print 1
    }
    else 
      //print 0
  }
}

【讨论】:

  • 不确定 OP 技能水平,但从他的问题来看,这种方法可能有点过分(无意冒犯 OP 只是想提供帮助)。对他来说可能更容易打破它,你不觉得吗?而不是在Map 中有Map。我还是喜欢这个。
  • @Robert 你能详细说明一下吗?
  • 添加了一些代码阐述,如果有什么令人困惑的地方请告诉我