Коллекции Java Использование денежных диапазонов - PullRequest
1 голос
/ 13 июля 2011

Я хотел бы хранить информацию в java-коллекции, которая кэшируется в памяти.

У меня есть следующая таблица

меньше, чем $ 1 - (сохранить некоторые данные)

От $ 1 до $ 115 000 - (Храните разные данные)

$ 115 001 до $ 345 000 - (Храните разные данные)

$ 345 001 до 580 000 - (Храните разные данные)

$ 580 001или больше - (сохраните некоторые другие данные)

Я бы хотел передать сумму денег в функцию.Затем мне нужно будет определить, в какой денежный диапазон попадают переданные деньги, чтобы я мог получить их данные.Например, было передано 127 000 долларов. Мне нужно было бы использовать данные третьих строк в приведенной выше таблице, потому что 127 000 находится между 115 000 и 345 000 долларов.

Я действительно буду признателен за любые предложения о том, как лучше спроектировать это..

Заранее спасибо, Даг

Ответы [ 6 ]

1 голос
/ 13 июля 2011

Один из способов справиться с этим - NavigableSet:

NavigableSet<Integer> cutoffs = new TreeSet<Integer>();
cutoffs.addAll(Arrays.asList(Integer.MIN_VALUE, 0, 150000, 345000, 580000));

...

public void something(int amount) {
  switch (cutoffs.lower(amount)) {
    case Integer.MIN_VALUE:
      // below 1
    case 0:
      // 1 to 150000
    case 150000:
      // etc
    case 345000:
      // etc
    default:
      // etc
  }
}

Скорее всего, это будет немного эффективнее, чем простое if/else (при условии, что вы создаете набор cutoffs только один раз, и этот метод часто используется), но для такого простого примера, как ваш, что-то попроще будет хорошо, если не лучше.

1 голос
/ 13 июля 2011

Вот основной рабочий пример.Конечно, вы, вероятно, захотите использовать что-то кроме MAX_VALUE и MIN_VALUE в качестве внешних границ, и вы, вероятно, захотите использовать числа с плавающей точкой вместо целых.Полная реализация, вероятно, будет иметь CurrencyRange в качестве интерфейса, где вы можете иметь различные реализации для случаев «менее чем 1 $» и «более чем 580 000»:

private static final List<CurrencyRange> ranges = Arrays.asList(
        new CurrencyRange(Integer.MIN_VALUE, 0, "some data"),
        new CurrencyRange(1, 115000, "some data"),
        new CurrencyRange(115001, 345000, "some data"),
        new CurrencyRange(345001, 580000, "some data"),
        new CurrencyRange(580001, Integer.MAX_VALUE, "some data")
);

public String determineDataByAmount(int amount) {
    for (CurrencyRange range : ranges) {
        if (range.contains(amount)) {
            return range.getData();
        }
    }
    throw new IllegalStateException(
        "No suitable range found for amount: " + amount);
}

class CurrencyRange {
    private int lowerLimit;
    private int upperLimit;
    private String data;

    public CurrencyRange(int lowerLimit, int upperLimit, String data) {
        this.lowerLimit = lowerLimit;
        this.upperLimit = upperLimit;
        this.data = data;
    }

    public boolean contains(int amount) {
        return amount >= lowerLimit && amount <= upperLimit;
    }

    public String getData() {
        return data;
    }
}
1 голос
/ 13 июля 2011

Используйте бинарный поиск для улучшения производительности, когда:

private List<Double> ranges = Arrays.asList(1.0, 115000.0, 345000.0, 580000.0);

private int findRange(double amount) {
    final int idx = Collections.binarySearch(ranges, amount);
    return idx >= 0 ? idx : -idx - 1;
}

И тест:

public class RangeTest {

    @Test
    public void shouldReturnIndex() throws Exception {
        assertThat(findRange(0.5)).isEqualTo(0);
        assertThat(findRange(1.0)).isEqualTo(0);
        assertThat(findRange(1.01)).isEqualTo(1);

        assertThat(findRange(114000.0)).isEqualTo(1);
        assertThat(findRange(115000.0)).isEqualTo(1);
        assertThat(findRange(115001.0)).isEqualTo(2);

        assertThat(findRange(581000.0)).isEqualTo(4);
    }


}

Несколько заметок:

  • бинарный поиск в вашем сценарии кажется излишним, однако на самом деле это самая простая реализация без каких-либо явных циклов и какой-либо пользовательской логики
  • findRange() возвращает индекс диапазона, в который вы попадаете (количество диапазонов равно числу шагов + 1)
  • Вы должны определенно использовать BigDecimal, я использовал double только для упрощения примера
  • Реальные тесты должны быть короче и более наглядными
1 голос
/ 13 июля 2011

Условные выражения будут работать лучше всего.

function processMoney(int amount) {
    if(amount > 580000) {
        //do stuff
    else if (amount > 345000) {
        // do other stuff
    }
}

и т. Д.

0 голосов
/ 13 июля 2011

Со стороны кодирования это легко. Используйте polymorphisim, чтобы иметь разные объекты для каждой суммы денег.

Я понял, что вам нужно сохранить это и в базе данных. Хотя вы точно не сказали этого, интенсивное использование таких слов, как «таблица», «данные» и «строки», указывает на то, что вы заинтересованы в хранении базы данных. Чтобы сохранить полиморфные данные в базе данных, у вас есть только несколько вариантов:

  1. Наследование одной таблицы - использование одной таблицы для хранения всех классов в полиморфной иерархии.
  2. Наследование бетонных таблиц - использование одной таблицы для каждого конкретного подкласса.
  3. Наследование таблиц классов - использование одной таблицы для общего суперкласса и одной таблицы для каждого подкласса (конкретного или иного), хранящего поля в том виде, как они определены в объектно-ориентированной иерархии.

Преимущества для # 1 в том, что у вас есть только одна таблица для поиска, недостатком является то, что большая часть этой таблицы будет большим блоком вариантных данных. Часто поле с «вариантными» частями становится документом XML, хранящимся в строке. В любом случае, если нужно искать инвариантные (всегда там) поля, это легко; но если искать варианты полей, это становится трудно.

Преимущества для # 2 в том, что запросы к базе данных легко выполнять с помощью стандартных инструментов SQL. Недостатком является то, что вы должны принять особые меры предосторожности, чтобы не хранить одни и те же инвариантные ключи в коллекции таблиц дважды, поскольку это будет означать, что учетная запись № 5 является одновременно и учетной записью на 5 долларов, и на 50 000 долларов.

Преимущество для # 3 состоит в том, что структура базы данных имитирует иерархию классов, что может облегчить проблемы коллизии ключей в # 2 и, тем не менее, обеспечить лучшие SQL-запросы, чем # 1. Недостатком является то, что для получения любого отдельного объекта вам нужно выполнить соединение по внешнему ключу (снижение производительности).

Короче, без серебряных пуль. Однако, возможно, вы не имели в виду таблицы базы данных, в этом случае это не проблема.

0 голосов
/ 13 июля 2011
public void function(int money)
{
    if(money <= 1) //store some data
    if(money >= 2 && money <= 115000) // Store some different data
    if(money >= 115001 && money <= 345000) //Store some different data
    if(money >= 345001 && money <= 580000) //Store some different data
    if(money >= 580001) // Store some different data

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...