【问题标题】:'true' bool property counter method - is this efficient?'true' bool 属性计数器方法 - 这有效吗?
【发布时间】:2015-03-29 12:52:09
【问题描述】:

我有一个简单的方法可以检查特定对象的布尔属性有多少是真的。如果只有一个属性为真,它将返回相关字符串。但是,如果多个属性为 true,则返回 null。

public class HobbieSelector
{
    public bool Football { get; set; }
    public bool Tennis { get; set; }
    public bool Hockey { get; set; }
    public bool Basketball { get; set; }
    public bool Baseball { get; set; }
}

public string GetSelectedHobbie(HobbieSelector hobbie)
{
    var selectedHobbie = string.Empty;
    var count = 0;

    if(hobbie.Football)
    {
        selectedHobbie = "Football";
        count++;
    }
    if(hobbie.Tennis)
    {
        selectedHobbie = "Tennis";
        count++;
    }
    if(hobbie.Hockey)
    {
        selectedHobbie = "Hockey";
        count++;
    }
    if(hobbie.Basketball)
    {
        selectedHobbie = "Basketball";
        count++;
    }
    if(hobbie.Baseball)
    {
        selectedHobbie = "Baseball";
        count++;
    }

    return count == 1 ? selectedHobbie : null;
}

这段代码会运行多次,效率是最重要的。所以我只是想知道是否有任何更快更有效的方法来检查这个?

【问题讨论】:

  • 老实说,在我看来,枚举会更合适......如果有人传入选择器同时选择了“足球”和“网球”,为什么它应该返回 null?对我来说,这似乎是一个非常奇怪的设计。
  • 你的代码有一个明显的低效率。您一遍又一遍地将变量“selectedHobbie”设置为一个字符串,但如果选择了多个爱好,您将忽略所有设置工作并返回 NULL。它只是一个指针集,这并不可怕,但它不是“效率至上”

标签: c#


【解决方案1】:

如果有多个选择很常见,那么计数并不是最有效的方法,因为您可以在点击第二个true 后立即决定返回null

如果您想要尽可能高的效率,请使用位掩码。您可以使用一个非常简单的技巧来测试一个数字是否恰好将一位设置为1

bool exactlyOne = (mask & (mask-1)) == 0;

对于少量项目,您可以使用带有位掩码的查找表,如下所示:

public class HobbieSelector {
    private int mask;
    [Flags]
    private enum Masks {
        Football = 1
    ,   Tennis = 2
    ,   Hockey = 4
    ,   Basketball = 8
    ,   Baseball = 16
    }
    // This table encodes the smarts of the algorithm:
    // masks with more than one bit set are "mapped" to null,
    // while the five single-bit masks contain proper descriptions:
    private static string[] SelectionNames = new[] {
        null, "Football", "Tennis", null, "Hockey", null, null, null,
        "Basketball", null, null, null, null, null, null, null, "Baseball"
    };
    // Now the entire code boils down to indexing into an array
    public String GetSingleSelectionHobbie() {
        return SelectionNames[mask];
    }
    // The rest is an implementation of "packed" representation:
    public bool Football {
        get { return mask & Masks.Football != 0; }
        set { mask = value ? (mask | Masks.Football) : (mask & ~Masks.Football); }
    }
    public bool Tennis {
        get { return mask & Masks.Tennis != 0; }
        set { mask = value ? (mask | Masks.Tennis) : (mask & ~Masks.Tennis); }
    }
    public bool Hockey {
        get { return mask & Masks.Hockey != 0; }
        set { mask = value ? (mask | Masks.Hockey) : (mask & ~Masks.Hockey); }
    }
    public bool Basketball {
        get { return mask & Masks.Basketball != 0; }
        set { mask = value ? (mask | Masks.Basketball) : (mask & ~Masks.Basketball); }
    }
    public bool Baseball {
        get { return mask & Masks.Football != 0; }
        set { mask = value ? (mask | Masks.Football) : (mask & ~Masks.Football); }
    }
}

【讨论】:

  • 好吧,您编辑它以使用枚举,但按位 AND 可以使用 HasFlag 进行简化
【解决方案2】:

我会为此使用枚举

将枚举Hobby 设计为enum

[Flags]
public enum Hobby {
    None = 0,
    Football = 1,
    Tennis = 2,
    Hockey = 4,
    Baseball = 8,
    Basketball = 16
}

然后,在您的 HobbieSelector 类中添加一个名为 Hobby 的属性:

public class HobbieSelector
{
     public Hobby Hobby { get; set; }
}

现在您可以使用掩码设置Hobby 属性:

HobbieSelector selector = new HobbieSelector();
selector.Hobby = Hobby.Football | Hobby.Baseball;

您可以使用Enum.HasFlag 检查selector 是否有特定的爱好:

if(selector.Hobby.HasFlag(Hobby.Football)) 
{

}

最后,您可以使用 LINQ 扩展方法实现 one hobby check or null

    // This will also return null if there's no hobby selected or there're many.
   // In the other hand, if selector.Hobby has only 1 flag, it will return
   // the whole enumeration value for the single hobby
   // Enumeration.ToString("f") return the enumeration value name 
   // (f.e. "Basketball")
    return new [] { Hobby.Football, Hobby.Basketball, Hobby.Baseball, Hobby.Tennis, Hobby.Hockey }
                    .SingleOrDefault(hobby => selector.Hobby.HasFlag(hobby)).ToString("f"); 

【讨论】:

    猜你喜欢
    • 2013-05-11
    • 1970-01-01
    • 1970-01-01
    • 2016-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-12
    • 2012-01-18
    相关资源
    最近更新 更多