بأناقة تحديد ما إذا كان واحد أو أكثر منطقية هو "صحيح"

StackOverflow https://stackoverflow.com/questions/377990

  •  22-08-2019
  •  | 
  •  

سؤال

لدي مجموعة من خمسة قيم منطقية.إذا كان أكثر من واحد من هذه صحيحة أريد أن excecute وظيفة معينة.ما هي الطريقة الأكثر أناقة يمكنك التفكير التي من شأنها أن تسمح لي أن تحقق هذا الشرط في واحد إذا() البيان ؟ الهدف لغة C# ولكن أنا مهتم في حلول بلغات أخرى (طالما نحن لا نتحدث عن محددة المدمج في الوظائف).

واحدة مثيرة للاهتمام الخيار لتخزين القيم المنطقية في بايت هل حق التحول و مقارنتها مع الأصل بايت.شيء مثل if(myByte && (myByte >> 1)) ولكن هذا يتطلب تحويل منفصل القيم المنطقية إلى بايت (عن طريق bitArray?) و يبدو أن قليلا (يقصد التورية) الخرقاء... [تحرير]آسف, كان يجب أن يكون if(myByte & (myByte - 1)) [/عدل]

ملاحظة:وهذا بالطبع قريبة جدا من الكلاسيكية "عدد السكان", "جانبية إضافة" أو "المبالغة الوزن" مشكلة البرمجة - ولكن ليس تماما نفس الشيء.لا تحتاج أن تعرف كيف العديد من القطع ، إلا إذا كان أكثر من واحد.أملي هو أن هناك الكثير من أبسط طريقة لتحقيق هذا الهدف.

هل كانت مفيدة؟

المحلول

ماذا عن

  if ((bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + 
      (bool4? 1:0) + (bool5? 1:0) > 1)
      // do something

أو المعمم الطريقة سيكون...

   public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools)
    {
       int trueCnt = 0;
       foreach(bool b in bools)
          if (b && (++trueCnt > threshold)) 
              return true;
       return false;          
    } 

أو باستخدام LINQ كما اقترح إجابات أخرى:

    public bool ExceedsThreshold(int threshold, IEnumerable<bool> bools)
    { return bools.Count(b => b) > threshold; }

تحرير (لإضافة جويل Coehoorn اقتراح:(في .صافي 2.x في وقت لاحق)

    public void ExceedsThreshold<T>(int threshold, 
                      Action<T> action, T parameter, 
                      IEnumerable<bool> bools)
    { if (ExceedsThreshold(threshold, bools)) action(parameter); }

أو في .Net framework 3.5 وما بعدها:

    public void ExceedsThreshold(int threshold, 
            Action action, IEnumerable<bool> bools)
    { if (ExceedsThreshold(threshold, bools)) action(); }

أو امتدادا IEnumerable<bool>

  public static class IEnumerableExtensions
  {
      public static bool ExceedsThreshold<T> 
         (this IEnumerable<bool> bools, int threshold)
      { return bools.Count(b => b) > threshold; }
  }

استخدام عندئذ:

  var bools = new [] {true, true, false, false, false, false, true};
  if (bools.ExceedsThreshold(3))
      // code to execute  ...

نصائح أخرى

وكنت ذاهبا لكتابة نسخة ينق، ولكن خمسة أو حتى الناس بضربي لها. ولكن أنا حقا مثل هذا النهج بارامس لتجنب الاضطرار إلى الجديدة يدويا صفيف. لذلك أعتقد أن أفضل الهجين، استنادا إلى الإجابة روبية مع هيئة استبدال مع Linqness اضح:

public static int Truth(params bool[] booleans)
{
    return booleans.Count(b => b);
}

واضح جميل في القراءة، والاستخدام:

if (Truth(m, n, o, p, q) > 2)

ولقد حان الوقت للإجابة LINQ واجبة، وهو في هذه الحالة هو في الواقع أنيق جدا.

var bools = new[] { true, true, false, false, false };

return bools.Count(b => b == true) > 1;

وأود فقط أن يلقي لهم [إينتس] والمبلغ.

وإلا إذا كنت في حلقة داخلية فائقة ضيق، والذي يحتوي على فائدة من أن تكون سهلة الفهم.

وكنت أكتب وظيفة لاستقبال أي عدد من القيم المنطقية. فإنه إرجاع عدد تلك القيم التي تحققت. تحقق نتيجة لعدد من القيم التي تحتاج إلى أن تكون إيجابية أن تفعل شيئا.

والعمل بجد ليكون واضحا، وليس ذكي!

private int CountTrues( params bool[] booleans )
{
    int result = 0;
    foreach ( bool b in booleans )
    {
        if ( b ) result++;
    }

    return result;
}

وإذا كنت تقصد أكثر من أو يساوي منطقي واحد يساوي صحيح، هل يمكن أن تفعل ذلك مثل

if (bool1 || bool2 || bool3 || bool4 || bool5)

إذا كنت تحتاج إلى أكثر من واحد (2 وما فوق) القيم المنطقية يساوي صحيح، يمكنك أن تجرب

int counter = 0;
if (bool1) counter++;
if (bool2) counter++;
if (bool3) counter++;
if (bool4) counter++;
if (bool5) counter++;
if (counter >= 2) //More than 1 boolean is true

إذا كانت هناك الملايين بدلا من مجرد 5 هل يمكن تجنب عدد () وذلك بدلا من ذلك ...

public static bool MoreThanOne (IEnumerable<bool> booleans)
{
    return booleans.SkipWhile(b => !b).Skip(1).Any(b => b);
}

إذا كانت معبأة الأعلام الخاصة بك في كلمة واحدة ثم <وأ href = "https://stackoverflow.com/questions/377990/elegantly-determine-if-more-than-one-boolean-is-true/379947#379947 "> حل مايكل بير في ستعمل. ومع ذلك، فإن حلقة ليست ضرورية:

int moreThanOneBitSet( unsigned int v)
{
    return (v & (v - 1)) != 0;
}

مثال

 v (binary) | v - 1 | v&(v-1) | result
------------+-------+---------+--------
       0000 |  1111 |    0000 |  false
       0001 |  0000 |    0000 |  false
       0010 |  0001 |    0000 |  false
       0011 |  0010 |    0010 |   true
       .... |  .... |    .... |   ....
       1000 |  0111 |    0000 |  false
       1001 |  1000 |    1000 |   true
       1010 |  1001 |    1000 |   true
       1011 |  1010 |    1010 |   true
       1100 |  1011 |    1000 |   true
       1101 |  1100 |    1100 |   true
       1110 |  1101 |    1100 |   true
       1111 |  1110 |    1110 |   true

وأقصر وأقبح من الإصدار Vilx-ق:

if (((a||b||c)&&(d||e))||((a||d)&&(b||c||e))||(b&&c)) {}

ومن أعلى رأسي، واتباع نهج سريع لهذا المثال معينة. هل يمكن تحويل منطقي إلى int (0 أو 1). ثم يتكرر خلال الحراريات وإضافة لهم. إذا كانت النتيجة> = 2 ثم يمكنك تنفيذ الدالة.

وبينما أنا أحب LINQ، وهناك بعض الثقوب في ذلك، مثل هذه المشكلة.

والقيام العد على ما يرام بشكل عام، ولكن يمكن أن تصبح مشكلة عند البنود الخاصة بك عد يستغرق بعض الوقت لحساب / استرداد.

ووأي () طريقة تمديد على ما يرام إذا كنت ترغب فقط للتحقق من وجودها، ولكن إذا كنت تريد أن تحقق على الأقل ليس هناك بنيت في وظيفة من شأنها أن تفعل ذلك ويكون كسول.

في النهاية، لقد كتبت وظيفة للعودة صحيح إذا كان هناك ما لا يقل عن عدد معين من العناصر في القائمة.

public static bool AtLeast<T>(this IEnumerable<T> source, int number)
{
    if (source == null)
        throw new ArgumentNullException("source");

    int count = 0;
    using (IEnumerator<T> data = source.GetEnumerator())
        while (count < number && data.MoveNext())
        {
            count++;
        }
    return count == number;
}

لاستخدام:

var query = bools.Where(b => b).AtLeast(2);

وهذا له فائدة من عدم الحاجة إلى تقييم جميع البنود قبل أن تعود نتيجة لذلك.

[سد] مشروعي، NExtension يحتوي أتلست، AtMost وتجاوزات التي تسمح لك لخلط في المسند مع أتلست / معظم الاختيار. [/ التوصيل]

والصب ل[إينتس] وتلخيص يجب أن تعمل، لكنه قبيح قليلا وفي بعض اللغات قد لا يكون ممكنا.

وماذا عن شيء من هذا القبيل

int count = (bool1? 1:0) + (bool2? 1:0) + (bool3? 1:0) + (bool4? 1:0) + (bool5? 1:0);

وأو إذا كنت لا تبالي الفضاء، هل يمكن أن مجرد precompute الجدول الحقيقة واستخدام bools كما أدلة هي:

if (morethanone[bool1][bool2][bool3][bool4][bool5]) {
 ... do something ...
}

وأود أن تفعل شيئا من هذا القبيل، وذلك باستخدام حجة بارامس.

        public void YourFunction()
        {
            if(AtLeast2AreTrue(b1, b2, b3, b4, b5))
            {
                // do stuff
            }
        }

        private bool AtLeast2AreTrue(params bool[] values)
        {
            int trueCount = 0;
            for(int index = 0; index < values.Length || trueCount >= 2; index++)
            {
                if(values[index])
                    trueCount++;
            }

            return trueCount > 2;

        }
if (NumberOfTrue(new List<bool> { bool1, bool2, bool3, bool4 }) >= 2)
{
    // do stuff
}

int NumberOfTrue(IEnumerable<bool> bools)
{
    return bools.Count(b => b);
}

وليس بالضبط جدا ... ولكن هنا طريقة أخرى للقيام بذلك:

if (
    (a && (b || c || d || e)) ||
    (b && (c || d || e)) ||
    (c && (d || e)) ||
    (d && e)
)

ولدي واحد أفضل بكثير بكثير الآن وقصيرة جدا!

bool[] bools = { b1, b2, b3, b4, b5 };
if (bools.Where(x => x).Count() > 1)
{
   //do stuff
}

وكنت أرغب في إعطاء C ++ 11 variadic الجواب القالب.

template< typename T>
T countBool(T v)
{
    return v;
}

template< typename T, typename... Args>
int countBool(T first, Args... args)
{
    int boolCount = 0;
    if ( first )
        boolCount++;
    boolCount += countBool( args... );
    return boolCount;
}

والدعوة ببساطة على النحو التالي يخلق طريقة أنيقة بدلا من إحصاء عدد bools.

if ( countBool( bool1, bool2, bool3 ) > 1 )
{
  ....
}

في معظم لغات صحيح ما يعادل قيمة غير صفرية في حين كاذبة صفر. ليس لدي بناء الجملة الصحيح بالنسبة لك، ولكن في رمز زائف، وماذا عن:

if ((bool1 * 1) + (bool2 * 1) + (bool3 * 1) > 2)
{
    //statements here
}

إذا كان لديك سوى خمس قيم مختلفة، يمكنك القيام بذلك بسهولة الاختبار عن طريق التعبئة البتات في لفترة قصيرة أو عدد صحيح والتحقق لمعرفة ما إذا كان أي من الإجابات صفر أو واحد قليلا. إن الأرقام غير صالحة الوحيدة التي يمكن أن تحصل يكون ..

0x 0000 0000 
0x 0000 0001
0x 0000 0010
0x 0000 0100
0x 0000 1000
0x 0001 0000

وهذا يمنحك ستة القيم للبحث عن، ووضعها في جدول بحث وإذا لم يكن هناك، لديك إجابتك.

وهذا يعطيك إجابة بسيطة.

   public static boolean moreThan1BitSet(int b)
   {
      final short multiBitLookup[] = { 
            1, 1, 1, 0, 1, 0, 0, 0,
            1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0,
            1, 0, 0, 0, 0, 0, 0, 0,
            0, 0, 0, 0, 0, 0, 0, 0
      };
      if(multiBitLookup[b] == 1)
         return false;
      return true;
   }

وهذا لا مقياس جيد الماضي 8 بت، ولكن لديك خمسة فقط.

وإذا ((b1.CompareTo (كاذبة) + b2.CompareTo (كاذبة) + b3.CompareTo (كاذبة) + ...)> 1)

و// أكثر من واحد منهم صحيحة

...

آخر

...

ولقد ذكرت

<اقتباس فقرة>   

وخيار واحد للاهتمام هو لتخزين القيم المنطقية في بايت،   القيام تحول الحق ومقارنتها مع البايت الأصلي.   شيء من هذا القبيل if (myByte && (myByte >> 1))

وأنا لا أعتقد أن التعبير سوف تعطيك النتيجة التي تريدها (على الأقل باستخدام دلالات C، لأن عبارة غير صالح C #):

إذا (myByte == 0x08)، ثم التعبير سيعود صحيح على الرغم من أن هناك مجموعة واحدة فقط قليلا.

إذا كنت تعني "if (myByte & (myByte >> 1))" ثم إذا (myByte == 0x0a) التعبير سيعود كاذبة على الرغم من أن هناك 2 بت تعيينها.

ولكن هنا بعض التقنيات لحساب عدد البتات في كلمة واحدة:

بت

Twiddling المأجورون - بت العد

وهناك تباين قد تفكر في استخدام طريقة العد كيرنيغان، ولكن إنقاذ في وقت مبكر منذ تحتاج فقط لمعرفة ما إذا كان هناك أكثر من مجموعة واحدة بت:

int moreThanOneBitSet( unsigned int v)
{
    unsigned int c; // c accumulates the total bits set in v

    for (c = 0; v && (c <= 1); c++)
    {
      v &= v - 1; // clear the least significant bit set
    }

    return (c > 1);
}

وبطبيعة الحال، وذلك باستخدام جدول بحث ليست خيارا سيئا أيضا.

وكنت أعاني مؤخرا هذه المسألة نفسها، حيث كان لي ثلاثة القيم المنطقية، التي كنت بحاجة للتأكد من أن 1 فقط منهم كان صحيحا في وقت واحد. لهذا كنت المشغل XOR كما يلي:

bool a = true;
bool b = true;
bool c = false;

if (a || b || c)
{
    if (a ^ b ^ c){
        //Throw Error
    }
}

وهذا الرمز سوف رمي خطأ كما أ و ب على حد سواء صحيح.

لإشارة: http://www.dotnetperls.com/xor

ولقد وجدت فقط مجرد عامل XOR في C # إذا كان أي شخص يعرف أي حفرة تقع هذه الاستراتيجية، واسمحوا لي أن أعرف.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top