根据偏好从列表中选择一个元素

时间:2017-06-18 00:09:04

标签: java

我收到了此表单

的无序列表
class Element {
  String property; // has value from the set ("A", "B", "C", "D")
}

其中没有两个元素具有相同的property值 我想根据一组规则选择一个元素,如下所示,并返回其property值:

  1. 如果某个元素的property具有值"A",则选择该元素。
  2. 否则,如果某个元素的property具有值"B",则选择该元素。
  3. 否则,如果某个元素的property具有值"C",则选择该元素。
  4. 最后,如果尚未选择任何元素,则抛出异常。
  5. 这是我为此问题提出的一个解决方案:

    String chooseElementProperty(List<Element> elements) {
      // Iterates the list and creates a set of all the property values.
      // example: [{property: 'A'}, {property: 'B'}] -> {'A', 'B'}
      Set<String> propertyValues = pluckPropertyValues(elements);
    
      if (propertyValues.contains("A"))
        return "A";
      if (propertyValues.contains("B"))
        return "B";
      if (propertyValues.contains("C"))
        return "C";
      throw new IllegalArgumentException("Invalid input!");
    }
    

    我的问题是:有什么更好/更干净的方法可以让这种方法更具可扩展性,如果将来我想选择"B"超过"A",我会更容易改变我的偏好?

5 个答案:

答案 0 :(得分:4)

不是将所需的属性值硬编码到chooseElementProperty中,而是在另一个参数中提供它们:

String chooseElementProperty(List<Element> elements, List<String> prefs) {
  // Iterates the list and creates a set of all the property values.
  // example: [{property: 'A'}, {property: 'B'}] -> {'A', 'B'}
  Set<String> propertyValues = pluckPropertyValues(elements);

  for (String s: prefs) {
      if (propertyValues.contains(s))
          return s;
  }
  throw new IllegalArgumentException("Invalid input!");
}

我在这里使用了List<String>,但如果您愿意,也可以使用String[]甚至String... varargs。

答案 1 :(得分:3)

试试这个:

List<String> targets = Arrays.asList("A", "B", "C");
return elements.stream()
  .map(this::pluckPropertyValues)
  .flatMap(Set::stream)
  .filter(targets::contains)
  .sorted(Comparator.comparing(targets::indexOf))
  .findFirst()
  .orElseThrow(IllegalArgumentException::new);

这适用于任意目标列表,其偏好基于它们在列表中的位置。

免责声明:代码可能无法编译或工作,因为它在我的手机上被翻阅(但它有可能起作用)

答案 2 :(得分:3)

假设所有属性值都是字母,您可以对列表进行排序并提供comparatorpropery排序,然后验证第一项的属性

Collections.sort(elements, new Comparator<Element>() {
    @Override
    public int compare(Element a, Element b) {
        return a.property.compareTo(b.property);
    }
});
List<String> check = Arrays.asList("A", "B", "C");
String tmp = elements.get(0).property;
if check.contains(tmp) 
    return tmp
else
    throw new IllegalArgumentException("Invalid input!");

您还可以使用lambda进行排序:

Collections.sort(elements, (e1, e1) -> e1.property.compareTo(e2.property));

答案 3 :(得分:2)

目前的答案似乎假设订单是"A", "B", "C",因此可能忽略了最后一个重要的陈述:

  

如果以后我想选择"B"超过"A",那么这种方法可以更容易地改变我的偏好,那么这种方法更好/更干净的方法是什么?

除此之外,解决方案可能被视为......&#34;棘手&#34; ......或者从计算的角度看是复杂的。我投票选择与您类似的解决方案,但没有创建属性列表,并且基本上只是将首选项放入列表中以迭代它:

import java.util.Arrays;
import java.util.List;

class Element
{
    String property;

    Element(String property)
    {
        this.property = property;
    }
}
public class PickByPreference
{
    public static void main(String[] args)
    {
        List<Element> elements = Arrays.asList(
            new Element("B"),
            new Element("C"),
            new Element(null),
            new Element("A"));
        System.out.println(chooseElementProperty(elements));
    }

    static String chooseElementProperty(List<Element> elements) 
    {
        // Change this to change the preferences
        // (or pass it in as a parameter)
        List<String> preferences = Arrays.asList("A", "B", "C");

        for (String preference : preferences)
        {
            for (Element element : elements)
            {
                if (preference.equals(element.property))
                {
                    return element.property;
                }
            }
        }
        throw new IllegalArgumentException("Invalid input!");
    }
}

编辑:就渐近复杂性而言,将属性提取到Set可能是有益的,特别是如果你有许多元素。在这种情况下,实现将是

static String chooseElementProperty(List<Element> elements) 
{
    // Change this to change the preferences
    // (or pass it in as a parameter)
    List<String> preferences = Arrays.asList("A", "B", "C");
    Set<String> propertyValues = pluckPropertyValues(elements);
    for (String preference : preferences)
    {
        if (propertyValues.contains(preference))
        {
            return element.property;
        }
    }
    throw new IllegalArgumentException("Invalid input!");
}

答案 4 :(得分:1)

之前的答案是正确的。

我的两分钱是为了避免contains()使用indexOf()

所以使用

if (propertyValues.indexOf("A") > -1)
   return "A";
if (propertyValues.indexOf("B") > -1)
   return "B";
if (propertyValues.indexOf("C") > -1)
   return "C";