2009-03-24 16 views
16

Estoy seguro de que debe haber una forma mucho mejor de hacerlo. Estoy intentando hacer una operación de conteo en una enumeración de Flags. Antes estaba iterando sobre todos los valores posibles y contando las operaciones AND exitosas.Contando el número de banderas establecidas en una enumeración

p. Ej.

[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; 
} 

Estoy seguro de que debe haber una forma mejor de hacerlo, pero debe sufrir un bloqueo mental. ¿Alguien puede aconsejar una mejor solución?

+0

¿Sería más claro si usted está tratando de averiguar el número total de banderas en Habilidades sí Enum? o la cantidad de habilidades enum valor aplicado en "habilidades"? – Sung

+0

Definitivamente leí mal esto. Parece que está intentando contar el número de bits que están encendidos, no el número de elementos en la enumeración. Eliminé mi publicación. –

+0

Lo siento por no estar claro. De hecho, estoy tratando de contar el número de habilidades activas pasadas al método Count. Editará la pregunta ligeramente para que quede más clara. – Ian

Respuesta

5

Después de buscar en el sitio, Assaf sugirió que pude encontrar una solución ligeramente diferente que conseguí trabajando para Int32.

Aquí está el código para cualquier otra persona:

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

Esto solo funciona para enum de banderas con 32 o menos opciones. –

+0

Pero las enumeraciones de banderas están limitadas a 32 opciones de todos modos según la especificación, por lo que no hay problema. – Ian

+0

Si a alguien le interesa esto se llama Hemming wieght. Más detalles de la wikipedia: https://en.wikipedia.org/wiki/Hamming_weight – SOReader

-3

Enum.GetNames() devolverá una matriz de todos los nombres en la enumeración, agregue un .Length para encontrar el recuento.

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

Esto no responde la pregunta, léelo de nuevo –

3

La cuenta es equivalente a contar cuántos bits se establecen en 1 en el valor entero de la enumeración.

hay maneras muy rápidas de hacer esto en C/C++, que se puede adaptar a C#:

por ejemplo,

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; 
} 

Tomado de here.

EDITAR
enlace que está muerto. Encontrado another one que probablemente contiene el mismo contenido.

+0

Eso es más lo que busco sí. Aunque todavía no puedo ponerlo en funcionamiento. – Ian

+0

Es posible que tenga una mejor comprensión de esto que yo ... Actualmente estoy tratando de usar un UInt32 pero 033333333333 etc. no se lanzará a un UInt32. – Ian

+0

Utilizando ese sitio logré encontrar una publicación con un enfoque ligeramente diferente que me llevó a la solución. Gracias 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 

depende de la definición de "mejor".

se requiere la verificación de Skills.None porque si no hay bits activados, la cadena() devuelve Skills.None que da como resultado un conteo de 1. esto funcionaría igual para entero, largo y sus parientes sin firmar.

0

la única razón para utilizar este método es si las banderas no son contiguas y si las banderas se agregarán periódicamente.

<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 

if "better" significa que esto no es más rápido;) it.

27

El siguiente código le dará el número de bits que se establecen para un número determinado de cualquier tipo que varían en tamaño, desde byte hasta long.

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; 
} 

Este código es muy eficiente ya que sólo repite una vez para cada bit en lugar de una vez por cada bit sea posible, como en los otros ejemplos.

+4

¡Nifty! Entra en la bolsa de regalos! –

+1

@JohannGerell Quizás te guste la [respuesta] (http://stackoverflow.com/a/42557518/197591) ¡Acabo de publicar tu bolsa de regalos! :) – Neo

2

Una forma muy concisa hacerlo utilizando BitArray y LINQ:

public static int Count(Skills skillsToCount) 
{ 
    return new BitArray(new[] {(int)skillsToCount}).OfType<bool>().Count(x => x); 
} 
Cuestiones relacionadas