3

I want to create a new list with only the transactions from the input list that meet the following requirement: The name and code should be on the input list multiple times. (See example.) The items and ID are not relevant.

Input list

List<Transactions> transactionsList;
+----+------+----+-------+
| id | name |code|  item |
+----+------+----+-------+
| 1  | john | A1 | shoes |
| 2  | john | A1 | shirt |
| 3  | anon | A2 | shoes |
| 4  | anon | A2 | shoes |
| 5  |nymous| A3 | tie   |
+----+------+----+-------+

Expected result

+----+------+----+-------+
| id | name |code|  item |
+----+------+----+-------+
| 1  | john | A1 | shoes |
| 2  | john | A1 | shirt |
| 3  | anon | A2 | shoes |
| 4  | anon | A2 | shoes |
+----+------+----+-------+

I've tried using this code

List<Transactions> filteredTransactionList = new ArrayList<>();

for(Transactions transaction : transactionList){
    if (transactionList.stream().anyMatch(f -> 
        f.getName().equals(transaction .getName())) && 
        transactionList.stream().anyMatch(f -> f.getCode().equals(transaction .getCode())) ) {
                    filteredTransactionList.add(transaction );
    }
}

But it seems like this code won't work since the if condition will always be true when it found itself in the list

Is there any way to achieve it without using .stream if possible? Someone said that I can achieve it using map but I can't find the way to do so. It's fine using anything if there is no other option.

I'd have to keep the for loop for my other if() function.

lczapski
  • 4,026
  • 3
  • 16
  • 32
theokevin
  • 33
  • 4

2 Answers2

1

First you can create list of pair (name, code as list) that occurs more than one. Then use this list to filter.

List<List<String>> moreThenOneOccurs = transactionsList.stream()
    .map(t -> Arrays.asList(t.getName(), t.getCode()))
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
    .entrySet().stream().filter(e -> e.getValue() > 1)
    .map(Map.Entry::getKey)
    .collect(Collectors.toList());

List<Transactions> collect = transactionsList.stream()
    .filter(t -> moreThenOneOccurs.contains(Arrays.asList(t.getName(), t.getCode())))
    .collect(Collectors.toList());

UPDATE

If you want something without stream:

For creating list of duplicates, You can check this

Set<List<String>> moreThenOneOccurs = new HashSet<>();
Set<List<String>> set1 = new HashSet<>();
for (Transactions t : transactionsList) {
    if (!set1.add(Arrays.asList(t.getName(), t.getCode()))) {
        moreThenOneOccurs.add(Arrays.asList(t.getName(), t.getCode()));
    }
}

Then filtering can be done:

List<Transactions> filteredTransactionList = new ArrayList<>();
for(Transactions t : transactionList){
    if (moreThenOneOccurs.contains(Arrays.asList(t.getName(), t.getCode()))) {
        filteredTransactionList.add(t);
    }
}
Community
  • 1
  • 1
lczapski
  • 4,026
  • 3
  • 16
  • 32
0

I have no experience with the things you're using and this is not the fastest way to do it, but my answer will be an easy one to understand as a beginner.

Use a double for loop. 
for ( take a row to check if it has duplicates)
     for( go over all other rows to check if there is indeed a duplicate by comparing name 
          and code)
          If indeed a duplicate is found, print the row and go to the next. 

You can make it faster by printing all duplicate rows and removing them when you find them but this might become and issue if you want to keep thing sorted at all times. You can however sort them again in the end using their ID.

Sharon
  • 5
  • 4