2009-03-24 34 views
16

Tôi chắc chắn phải có cách tốt hơn để thực hiện việc này. Tôi đang cố gắng làm một hoạt động đếm trên một lá cờ enum. Trước khi tôi đã được itterating trên tất cả các giá trị có thể và đếm các thành công và hoạt động.Đếm số cờ được đặt trên một điều tra

ví dụ:

[Flags] 
public enum Skills 
{ 
    None = 0, 
    Skill1 = 1, 
    Skill2 = 2, 
    Skill3 = 4, 
    Skill4 = 8, 
    Skill5 = 16, 
    Skill6 = 32, 
    Skill7 = 64, 
    Skill8 = 128 
} 

public static int Count(Skills skillsToCount) 
{ 
    Skills skill; 
    for (int i = 0; i < SkillSet.AllSkills.Count; i++) 
    { 
     skill = SkillSet.AllSkills[i]; 
     if ((skillsToCount & skill) == skill && skill != Skills.None) 
     count++; 
    } 
    return count; 
} 

Tôi chắc chắn phải có cách tốt hơn để làm điều này, nhưng phải chịu đựng một khối tâm thần. Bất cứ ai có thể tư vấn cho một giải pháp đẹp hơn?

+0

bạn sẽ được rõ ràng hơn cho dù bạn đang cố gắng tìm ra tổng số cờ trong Kỹ năng Enum bản thân? hoặc số lượng kỹ năng enum giá trị áp dụng trên "kỹ năng"? – Sung

+0

Tôi chắc chắn đã hiểu sai điều này. Có vẻ như anh ấy đang cố gắng đếm số lượng bit được bật, không phải số lượng mục trong liệt kê. Tôi đã xóa bài đăng của mình. –

+0

Xin lỗi vì không rõ ràng. Thật vậy, tôi đang cố gắng đếm số lượng các kỹ năng hoạt động được chuyển vào phương thức Count. Sẽ chỉnh sửa câu hỏi một chút để làm cho nó rõ ràng hơn. – Ian

Trả lời

5

Sau khi tìm kiếm trên trang web Assaf đề xuất tôi đã tìm được giải pháp hơi khác một chút mà tôi đã làm việc cho Int32's.

Dưới đây là các mã cho bất cứ ai khác:

internal static UInt32 Count(this Skills skills) 
    { 
     UInt32 v = (UInt32)skills; 
     v = v - ((v >> 1) & 0x55555555); // reuse input as temporary 
     v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp 
     UInt32 c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count 
     return c; 
    } 
+1

Tính năng này chỉ hoạt động với các cờ enums có 32 tùy chọn trở xuống. –

+0

Nhưng Enums cờ được giới hạn trong 32 tùy chọn anyway theo spec để đó không phải là một vấn đề. – Ian

+0

Nếu ai đó quan tâm đến điều này được gọi là Hemming wieght. Thông tin chi tiết từ wikipedia: https://en.wikipedia.org/wiki/Hamming_weight – SOReader

-3

Enum.GetNames() sẽ trả về một mảng của tất cả các tên trong enum, thêm một .Length để tìm số.

-2
int count = Enum.GetValues(typeof(Skills)).Length; 
+2

Điều này không trả lời được câu hỏi, hãy đọc lại câu hỏi –

3

Số đếm tương đương với việc đếm số lượng bit được đặt thành 1 trong giá trị nguyên của enum.

Có những cách rất nhanh để thực hiện việc này trong C/C++, mà bạn có thể thích ứng với C#:

ví dụ:

int bitcount(unsigned int n) { 
    /* works for 32-bit numbers only */ 
    /* fix last line for 64-bit numbers */ 

    register unsigned int tmp; 

    tmp = n - ((n >> 1) & 033333333333) 
      - ((n >> 2) & 011111111111); 
    return ((tmp + (tmp >> 3)) & 030707070707) % 63; 
} 

Lấy từ here.

EDIT
Liên kết được cung cấp đã chết. Tìm thấy another one có thể chứa cùng một nội dung.

+0

Đó là những gì tôi có sau khi có. Mặc dù không thể làm cho nó hoạt động được. – Ian

+0

Bạn có thể có một sự hiểu biết tốt hơn về điều này mà tôi ... Hiện tại tôi đang cố gắng sử dụng một UInt32 nhưng 033333333333 vv sẽ không đúc một UInt32. – Ian

+0

Sử dụng trang web đó, tôi đã quản lý để tìm một bài đăng có cách tiếp cận hơi khác so với cách đưa tôi đến giải pháp. Cảm ơn Assaf. – Ian

0
<FlagsAttribute()> _ 
Public Enum Skills As Byte 
    None = 0 
    Skill1 = 1 
    Skill2 = 2 
    Skill3 = 4 
    Skill4 = 8 
    Skill5 = 16 
    Skill6 = 32 
    Skill7 = 64 
    Skill8 = 128 
End Enum 


    Dim x As Byte = Skills.Skill4 Or Skills.Skill8 Or Skills.Skill6 
    Dim count As Integer 
    If x = Skills.None Then count = 0 Else _ 
     count = CType(x, Skills).ToString().Split(New Char() {","c}, StringSplitOptions.RemoveEmptyEntries).Count 

phụ thuộc vào định nghĩa của "tốt hơn".

kiểm tra Skills.None là bắt buộc vì nếu không có bit, chuỗi() trả về Skills.None có kết quả là số 1. điều này sẽ làm việc giống nhau cho số nguyên, dài và người thân chưa ký.

0

lý do duy nhất để sử dụng phương pháp này là nếu cờ không tiếp giáp và nếu cờ sẽ được thêm định kỳ.

<FlagsAttribute()> _ 
Public Enum Skills As Integer 
    Skill1 = CInt(2^0) 'bit 0 
    Skill2 = CInt(2^1) 
    Skill3 = CInt(2^2) 
    Skill4 = CInt(2^3) 
    Skill5 = CInt(2^4) 
    Skill6 = CInt(2^5) 
    Skill7 = CInt(2^6) 
    Skill8 = CInt(2^7) 
    Skillx = CInt(2^10) 'bit 10, some bits were skipped 
End Enum 


    Dim mySkills As Integer = Skills.Skillx Or Skills.Skill4 Or Skills.Skill8 Or Skills.Skill6 
    Dim count As Integer 'count of bits on 
    count = CType(mySkills, Skills).ToString().Split(New Char() {","c}, _ 
                StringSplitOptions.RemoveEmptyEntries).Count 

nếu "tốt hơn" có nghĩa là nhanh hơn thì không;).

27

Mã sau đây sẽ cung cấp cho bạn số lượng bit được đặt cho một số lượng nhất định thuộc bất kỳ loại nào có kích thước khác nhau từ byte đến dài.

public static int GetSetBitCount(long lValue) 
{ 
    int iCount = 0; 

    //Loop the value while there are still bits 
    while (lValue != 0) 
    { 
    //Remove the end bit 
    lValue = lValue & (lValue - 1); 

    //Increment the count 
    iCount++; 
    } 

    //Return the count 
    return iCount; 
} 

Mã này rất hiệu quả vì nó chỉ lặp lại một lần cho mỗi bit thay vì một lần cho mỗi bit có thể như trong các ví dụ khác.

+4

Tiện lợi! Đi vào túi goodie! –

+1

@JohannGerell Bạn có thể thích [answer] (http://stackoverflow.com/a/42557518/197591) Tôi vừa mới đăng cho chiếc túi goodie của bạn! :) – Neo

2

Một cách rất súc tích để làm điều đó bằng BitArray và LINQ:

public static int Count(Skills skillsToCount) 
{ 
    return new BitArray(new[] {(int)skillsToCount}).OfType<bool>().Count(x => x); 
} 
Các vấn đề liên quan