Как представить 4 логических возможности в одном значении

Я хочу сохранить 4 логических возможности в одном значении. Например, мне нужно одно значение, которое сообщает, является ли человек:

IsSingle
IsGraduate
IsMale
IsLookingForPartner

Так хорошо ли хранить их в байте, у которого может быть выделено 4 бита, по одному на каждый параметр. Если бит установлен в 1, то этот логический параметр является истинным. Так что я могу выполнять операции сдвига битов, чтобы найти, что все верно. если значение байта равно 111, то первые три параметра верны. Это хороший способ? Есть ли лучший способ реализовать это?

Мне нужно сохранить это значение как один параметр в базе данных.


person Rajat Gupta    schedule 12.03.2011    source источник


Ответы (8)


Битовые флаги.

public static final int IsSingle = 1 << 0;
public static final int IsGraduate = 1 << 1;
public static final int IsMale = 1 << 2;
public static final int IsLookingForPartner = 1 << 3;

...

if ((Value & IsSingle) != 0) {
}

if ((Value & IsGraduate) != 0) {
}

// Set "Single"
Value |= IsSingle;

// Remove "Graduate"
Value &= ~IsGraduate;
person Erik    schedule 12.03.2011

Это действительно возможно, но не рекомендуется.

Что, если вы хотите найти в своей базе данных всех одиноких студентов? Или Мужской? Хотя пространство, которое вы экономите, минимально, вы отказываетесь от возможности индексировать свои данные не только для более быстрого поиска, но и для поиска любых данных, которые имеют критерии запроса, зависящие от любого из этих атрибутов, вам нужно будет выполнять операции сдвига битов для всех записей (или проверки нескольких целочисленных значений), что в конечном итоге будет ужасно медленным.

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

person Anastasiosyal    schedule 12.03.2011

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

enum Interest {
   IsSingle,
   IsGraduate,
   IsMale,
   IsLookingForPartner 
}

EnumSet<Interest> interests = EnumSet.of(Interest.IsSingle, Interest.IsMale);

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

person Peter Lawrey    schedule 12.03.2011

Используйте бинарную упаковку. Определите константы для них как:

IsSingle = 1;
IsGraduate = 2;
IsMale = 4;
IsLookingForPartner = 8;

И объедините их с помощью логической операции ИЛИ. Таким образом, каждая возможность будет представлена ​​битом в двоичном представлении числа. Вы можете проверить с помощью операции И упакованное значение с любой из констант:

short status = IsSingle | IsMale;    // will give 5

if ((status & IsMale) != 0)
    System.out.println("Male.");
person vbence    schedule 12.03.2011

Рассматривали ли вы использование байта для хранения значений? Затем вы можете сделать что-то вроде следующего:

public Byte setDetails(bool isSingle, bool isGraduate, bool isMale, bool isLooking)
{
    Byte result = 0;

    //Set the details
    if (isSingle) result = result | 1;
    if (isGraduate) result = result | 2;
    if (isMale) result = result | 4;
    if (isLooking) result = result | 8;

    return result;
}

Затем позже вы можете использовать такой код:

Byte details = getDetails(true, false, true, false);
bool isSingle = (details & 1) != 0;

чтобы узнать подробности.

... Тем не менее, ради трех байтов стоит ли вся дополнительная работа и константы?

person Karl Nicoll    schedule 12.03.2011
comment
Ваш код не компилируется. Это boolean, а не bool, и вам также нужно заменить result = result | 1 на result = (byte)(result | 1) и так далее. - person Luke Woodward; 12.03.2011
comment
@ Люк - Моя ошибка, я наспех, не проверив. Надо было поставить оговорку. - person Karl Nicoll; 13.03.2011

Лучше всего будет boolean[4], где вы сохраните каждое значение в отдельной ячейке массива, и это займет минимум места!

напишите этот фрагмент кода в своем классе:

private boolean[] values = new boolean[4];

void setValue(String name, boolean value){
    if(name=="IsSingle")
        values[0] = value;
    else if(name=="IsGraduate")
        values[1] = value;
    else if(name=="IsMale")
        values[2] = value;
    else if(name=="IsLookingForPartner")
        values[3] = value;
}

boolean getValue(String name){
    if(name=="IsSingle")
        return values[0];
    else if(name=="IsGraduate")
        return values[1];
    else if(name=="IsMale")
        return values[2];
    else if(name=="IsLookingForPartner")
        return values[3];
    else
        return false;
}

теперь просто используйте это как: setValue("IsGraduate", true); getValue("IsMale");

person Vladp    schedule 12.03.2011

Если вы хотите использовать решение просто для развлечения, это нормально, но если это будет профессиональное приложение, НЕ реализуйте это в одном параметре в базе данных. Если вы это сделаете, подумайте об изменениях в бизнесе:

  1. Удалить isLookingForPartner // избыточный бит будет все время - порядок имеет значение
  2. Добавить новые параметры
  3. Найти всех людей, которые isLookingForPartner==true //будет медленным
person lukastymo    schedule 12.03.2011

Вы действительно должны использовать отдельные переменные для их хранения. Человек может быть выпускником, холостым, мужчиной и ищет партнера. Вы просто не можете хранить все эти возможности в одном логическом значении.

person FreeAsInBeer    schedule 12.03.2011