Forum Discussion
Filter Function to be optional depending on blank and non blank values
Jn12345
Without seeing your data structure, it is hard to say, but here is a general approach that I refer to as "masking." Rather than using filter like filter(target_array, filter_array=filter_value), you do let(filter_mask, filter_array=filter_value, filter(target_array, filter_mask). In this way, you are giving the filter function an array of boolean values (true or false) rather than asking it to evaluate whether some comparison/operation is true or false.
The reason this is useful is because in your let formula, you can pick and name each of your three (or four or five) filter columns, pick and name each of your filter values, and then use boolean functions to combine them. So (f_array_1 = "blue")*(f_array_2>5) is the same thing as saying "tell me which rows in these two arrays have "blue" in the first array and a number greater than 5 in the second. If you want to combine the filters with "and", but you haven't yet decided what the filter value should be, you can just multiply your f_array_1 mask by TRUE to have it return true for all rows satisfying your one filter. The formula below basically says, if there is a value in any one of these three columns in the current row, use that value for a filter mask on the specified column, and return all values in the target_array where it satisfies all of the required filters. This means that the first, second, or third filter values can be blank or have a value and the filtered array returned will be everything (if no values supplied) all the way down to nothing (if no value meets all of the criteria you have specified). So you can fill in the third value first, last, or second - it makes no difference. Your filtered list will always represent the values that meet all of the specified criteria.
If you prefer that your filter be that the return list simply meets one of the filter criteria (i.e. f1 or f2 or f3), then you can add the filter masks instead of multiplying them. You can also do whatever other boolean algebra you want on them.
You can change the names to your preference or add/remove filter columns and values. You must, however, properly reference the cells where your filter values are, the ranges where your filter columns and target columns are, and your operators for each filter (=, <>, >, <, etc.). The isblank can be temperamental if the cell referred to is not truly blank (has no value whatever) but is something like an empty string, i.e. =""
let(
value_array_for_list, SERIAL_NUMBERS_REF,
first_column_to_filter_by, PRODUCT_TYPE_COLUMN_REF,
second_column_to_filter_by, PRODUCT_STYLE_COLUMN_REF,
third_column_to_filter_by, PRODUCT_COLOR_COLUMN_REF,
value_to_filter_first_column_by, [@[type]],
value_to_filter_second_column_by, [@[sytle]],
value_to_filter_third_column_by, [@[color]],
first_column_mask, if(isblank(value_to_filter_first_column_by), TRUE, value_to_filter_first_column_by = first_column_to_filter_by),
second_column_mask, if(isblank(value_to_filter_second_column_by), TRUE, value_to_filter_second_column_by = second_column_to_filter_by),
third_column_mask, if(isblank(value_to_filter_third_column_by), TRUE, value_to_filter_third_column_by = third_column_to_filter_by),
combined_mask, first_column_mask*second_column_mask*third_column_mask,
filtered_serial_numbers, filter(value_array_for_list, combined_mask, "No matching serial numbers"),
filtered_serial_numbers
)
- joelb95Sep 24, 2024Brass Contributor
I spent way more time on this than I should have, but I think there isn't a great answer due to validation limitations. My final suggestion to you is in some ways a poor second to one that PeterBartholomew1 appears to have come up with involving using the cell() formula to return the address of the last active cell for purposes of setting your filters and generating your validation arrays. What I would have done is created a helper column that requires you to check the row that you want to validate in order to update your filter arrays.
In any event, here is a file that has some of what I tried for you. You could, theoretically, adapt my formulas to your purpose relatively easily and expand them as necessary.validation_filter=lambda( choice, equip_val, make_val, model_val, serial_val, =LET( equip_col, tbl_equipment_list[Equipment Type], make_col, tbl_equipment_list[Make], model_col, tbl_equipment_list[Model], serial_col, tbl_equipment_list[Serial Number], mask_func, LAMBDA(value, column, IF(ISBLANK(value), EXPAND(TRUE, ROWS(column), 1, TRUE), value = column) ), equip_mask, mask_func(equip_val, equip_col), make_mask, mask_func(make_val, make_col), model_mask, mask_func(model_val, model_col), serial_mask, mask_func(serial_val, serial_col), combined_mask, equip_mask * make_mask * model_mask * serial_mask, no_box_checked, IFERROR( AND(NOT(equip_val), NOT(make_val), NOT(model_val), NOT(serial_val)), FALSE ), equip_choices, UNIQUE(FILTER(equip_col, combined_mask, "")), make_choices, UNIQUE(FILTER(make_col, combined_mask, "")), model_choices, UNIQUE(FILTER(model_col, combined_mask, "")), serial_choices, UNIQUE(FILTER(serial_col, combined_mask, "")), pick_choice_list, LAMBDA(choice, CHOOSE(choice, equip_choices, make_choices, model_choices, serial_choices) ), return_all, LAMBDA(choice, CHOOSE(choice, equip_col, make_col, model_col, serial_col)), result, IF(no_box_checked, return_all(choice), pick_choice_list(choice)), result )) valid_makes=XLOOKUP("x", tbl_results[filter_row], tbl_results[make], FALSE) valid_model=XLOOKUP("x", tbl_results[filter_row], tbl_results[model], FALSE) valid_serial_numbers=XLOOKUP("x", tbl_results[filter_row], tbl_results[serial_number], FALSE) valid_types=XLOOKUP("x", tbl_results[filter_row], tbl_results[type], FALSE)
- Jn12345Oct 03, 2024Brass ContributorLegend, Thank you! I wasn't able to do everything I wanted but this definitely set me in the right direction! thank you a ton.