Dúver Cruz
Dúver Cruz

Reputation: 348

Filter ArrayList multiple times in Java

I need to filter an ArrayList each time that user input a string in a textbox or/and click a button to add boolean attribute to filters.

public class ItemULD {
    private int idULD;
    private String contour;
    private String numULD;
    private boolean withNet;
}

And I tried with this method to filter the string in textbox

List<Integer> ids = grupoChip.getCheckedChipIds();
 for (Integer id : ids) {
   Chip chip = grupoChip.findViewById(id);
    ArrayList<ItemULD> arrayFiltered; = new ArrayList<>();
    for (ItemULD uld : arrayULD) {
      String num = String.valueOf(uld.getNumULD());
       if (num.contains(chip.getText()) || uld.getContour().contains(chip.getText())) {
        if (!arrayFiltered.contains(uld))
         arrayFiltered.add(uld);
       }
    }

 //Method to filter ULD's with net
    public static List<ItemULD> filters(List<ItemULD> allULD, boolean net){
            List<ItemULD> list = new ArrayList<>();
            for (ItemULD uld : allULD) {
                if (!net || uld.iswithNet()) {
                    list.add(uld);
                }
            }
            return list;
        }

The problem is when I try to add a new filter on the filtered results that didn't works.. E.G. I have this.

idULD:1,
contour:EK, 
numULD: 123456,
withNet:1

idULD:2,
contour:AF, 
numULD: 652466,
withNet:0

idULD:3,
contour:AF, 
numULD: 123663,
withNet:0

If I put on my seach textbox 123 I see 2 results id1 & id3 this is ok, but when I add AF I see two AF not only the match AF + 123 that would be the id3.

On the other hand, if I click the option to filter by attribute withNet I see all the results. I guess this is caused because I'm creating a new array in the method to return but, how I could do it?

EDIT

I use a ChipGroup to add Chip elements with the string that user write in a textbox. Then I iterate the ChipGroud to get the text of every Chip. So if the user write "123" + Enter a new Chip is added to the group

Upvotes: 0

Views: 461

Answers (1)

bertilmuth
bertilmuth

Reputation: 286

An extendable way of solving this is creating an interface Filter, something like this:

interface Filter{
  // This method checks if the filter is applied for the provided itemText.
  // For example, if the filter is a numULD filter, it returns true 
  // iff the itemText is a number. 
  boolean isApplicableTo(String itemText);

  // This method applies the filter. It returns true if the resulting list
  // shall contain the item, and false if the item shall not appear in the
  // list. For example, for the contour filter, the return value of the method is 
  // item.getContour().contains(itemText)
  boolean applyTo(ItemULD item, String itemText); 
}

Now create three classes implementing this interface, one for contour, one for numULD, and one for withNet. Create instances of these classes and put them in a collection. Iterate over the collection and check if the filter is applicable and if yes, apply the filter. And then perform an and operation (&&) on the result, starting with a variable boolean result = true;

If you've done that, you could even move this method to its own class Filtersthat takes several filters as arguments and returns the filtered result list.

EDIT: Here's a code example.

This is a test class that checks that the filter works correctly:

class FiltersTest {

    @Test
    void testsFilters() {
        Filter contourFilter = new ContourFilter();
        Filter numFilter = new NumFilter();
        Filters filters = new Filters(contourFilter, numFilter);
        
        ItemULD item1 = new ItemULD(1, "EK", "123456", true);
        ItemULD item2 = new ItemULD(2, "AF", "652466", false);
        ItemULD item3 = new ItemULD(3, "AF", "123663", false);
        List<ItemULD> items = Arrays.asList(item1, item2, item3);
        
        List<Chip> chips = Arrays.asList(new Chip("AF"), new Chip("123"));
        
        assertEquals(Arrays.asList(item3), filters.applyToItems(items, chips));
    }
}

These are the filter classes, based on the filter interface shown above:

class ContourFilter implements Filter{
    @Override
    public boolean isApplicableTo(String itemText) {
        // Place your RegEx check here
    }

    @Override
    public boolean applyTo(ItemULD item, String itemText) {
        String contour = item.getContour();
        return contour.contains(itemText);
    }   
}

class NumFilter implements Filter{
    @Override
    public boolean isApplicableTo(String itemText) {
        if (itemText == null) {
            return false;
        }
        try {
            Integer.parseInt(itemText);
        } catch (NumberFormatException nfe) {
            return false;
        }
        return true;
    }

    @Override
    public boolean applyTo(ItemULD item, String itemText) {
        String num = String.valueOf(item.getNumULD());
        return num.contains(itemText);
    }   
}

The filters class could look like this:

class Filters{
    private final List<Filter> filtersList;

    public Filters(Filter... filters) {
        this.filtersList = Arrays.asList(filters);
    }
    
    
    public List<ItemULD> applyToItems(List<ItemULD> items, List<Chip> chips) {
        List<ItemULD> filteredItems = new ArrayList<>();
        
        for (ItemULD item : items) {
            if(applyToItem(item, chips)) {
                filteredItems.add(item);
            }
        }
        
        return filteredItems;
    }
    
    public boolean applyToItem(ItemULD item, List<Chip> chips) {
        boolean result = true;
        
        for (Chip chip : chips) {
            String chipText = chip.getText();
            for (Filter filter : filtersList) {
                if(filter.isApplicableTo(chipText)) {
                    result = result && filter.applyTo(item, chipText);
                }
            }
        }
        
        return result;
    }
}

The Chip class is only a simplified version:

class Chip{
    private final String text;

    public Chip(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }
}

Upvotes: 1

Related Questions