0

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

2
  • Can you clarify if you have a single search text box (in total) or if you multiple search text boxes? In which variable is the text box stored, is it chip? If yes, it is unclear to me why the code would work for multiple criteria within the same text box (i.e. AF + 123), since you check if the complete text is contained: num.contains(chip.getText()) || uld.getContour().contains(chip.getText()) Commented Jun 20, 2022 at 10:41
  • I edited the question to add more info, I use a GroupChip to add a new chip when user write something in one textbox. Commented Jun 20, 2022 at 11:18

1 Answer 1

1

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;
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Okay I'm trying, I created the interface + contour class but, how I should apply the filter on the list of items if I have them in the other class ItemULD. In isApplicableTo I use a Regex to check it but in 'applyTo(String itemText)' should I add applyTo(String itemText, ArrayList<ItemULD>) or how can I apply the filter.. ? Thanks
No, you don‘t modify the list in the interface implementation. You just move the contents of the if clause (the conditional check only) to that class. Your calling code then adds the item to the list - as before.
I edited the interface (the applyTo() method needs the item). I will try to provide a working code example.
THANK YOU SO MUCH, work like a charm. I was stuck and tired to try so much things :(

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.