4

Input:

10101
11100

I would like to store this two strings in a datatype so that I can call the | OR operator on the two.

Here is my code:

        var g = new byte[2][];

        g[0] = "10101".Select(item => byte.Parse(item.ToString())).ToArray();
        g[1] = "11100".Select(item => byte.Parse(item.ToString())).ToArray();

        //won't compile
        Console.WriteLine(g[0] | g[1]);

The compiler error I am getting is:

Cannot apply operator '|' to operands byte[] and byte[]

I have also tried BitArray but this didn't seem right either. And I tried byte.Parse("10101") which just causes an overflow, this makes some sense to me.

What I am trying to do is OR the bits of both strings and the result would = 1, perhaps I need to shift through the bits in a for loop, I thought maybe I could just OR both binary representations of the matching length binary strings

Obviously I am choosing the wrong data type, byte[], to store my binary strings, I am just not experienced enough to know how to represent these binary strings in the right data type.

UPDATE

It's difficult to chose a correct answer because there are multiple correct answers. Just wanted to be clear that there is multiple solutions to this question presented that are good answers.

My question resulted from a problem I am trying to solve on HackerRank: https://www.hackerrank.com/challenges/acm-icpc-team

"You are given a list of N people who are attending ACM-ICPC World Finals. Each of them are either well versed in a topic or they are not. Find out the maximum number of topics a 2-person team can know. And also find out how many teams can know that maximum number of topics."

Thanks to help I received on Stack Overflow I came up with a not to bad solution:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Solution {
static void Main(String[] args) {
    var inputArr = Console.ReadLine().Split(' ').Select(item => int.Parse(item)).ToArray();
    var n = inputArr[0];
    var m = inputArr[1];


    var g = new byte[n];
    var team = new List<byte>();

    var teamsKnowMax = 0;
    var maxTopics = byte.MinValue >> sizeof(byte) * 8 - m;

    for(var i = 0; i < n; i++){
        g[i] = Convert.ToByte(Console.ReadLine(), 2);
        maxTopics = maxTopics | g[i];
    }

    for(var j = 0; j < n -1; j++){
        for(var k = j+1; k < n; k++){
            var or = g[j] | g[k];
            if((or & maxTopics) == maxTopics)
                teamsKnowMax++;
        }
    }

    Console.WriteLine(Convert.ToString(maxTopics,2).ToCharArray().Count(item => item == '1'));
    Console.WriteLine(teamsKnowMax);
}

}

But I failed to consider the constraints:

2≤N≤500 
1≤M≤500

So now I will need to work on a solution that breaks long binary strings into 8 bit chunks like an area of bytes that breaks up the long binary string and see if that works, rather than do that than go through each character of the string.

Initially I started to break up large binary strings into segments of 8, and deal with a reminder if there was one, this created a complex data structure that I couldn't manage. So often, solving these algorithms is about choosing the right data structure from the start. Then I went back to a BitArray and this gave me something I could | OR even if the binary string was very large. Credit to this link and content providers: https://codereview.stackexchange.com/questions/80458/acm-icpc-team-challenge-on-hackerrank-easy

   static void Main(String[] args) {
    var input = Console.ReadLine().Split(' ').Select(item => int.Parse(item)).ToArray();
    var N = input[0];
    var M = input[1];
    var maxTopics = 0;
    var maxTeams = 0;
    var bitArray = new BitArray[N];

    for(var n = 0; n < N; n++){
        bitArray[n] = new BitArray(M);

        var topics = Console.ReadLine();

        for(var m = 0; m < M; m++){
            bitArray[n].Set(m, topics[m] == '1');
        }
    }

    for(int i = 0; i < N -1; i ++){
        for(int j = i + 1; j < N; j++){
            var tempTopics = BitsOnCount(new BitArray(M).Or(bitArray[i]).Or(bitArray[j]));

            if (tempTopics > maxTopics){
                maxTopics = tempTopics;
                maxTeams = 1;
            }else if(tempTopics == maxTopics){
                maxTeams++;
            }

        }
    }

    Console.WriteLine(maxTopics);
    Console.WriteLine(maxTeams);
}

static int BitsOnCount(BitArray bitArray)
{
    var count = 0;
    foreach (var bit in bitArray)
    {
        if ((bool) bit)
            count++;
    }

    return count;
}
Community
  • 1
  • 1
Brian Ogden
  • 18,439
  • 10
  • 97
  • 176

4 Answers4

5

The solution with only manipulating numbers, without loops, LINQ, etc. Should be the best performance.

var str1 = "10101";
var str2 = "11100";

var num1 = Convert.ToByte(str1, 2);
var num2 = Convert.ToByte(str2, 2);
var or = num1 | num2;

// We need to lookup only that bits, that are in original input values.
// So, create a mask with the same number of bits.
var mask = byte.MaxValue >> sizeof(byte) * 8 - Math.Max(str1.Length, str2.Length);
var result = (or & mask) == mask;

// True, when all bits after OR are 1, otherwise - False.
Console.WriteLine(result);
kyrylomyr
  • 12,192
  • 8
  • 52
  • 79
  • This is actually a much cleaner solution – victor Nov 11 '15 at 23:27
  • I tired this and this is fine except I am actually trying to OR each bit and I might have to use bit shifting – Brian Ogden Nov 11 '15 at 23:28
  • You can convert the result back to binary using BitConverter or Convert. Also, remeber that types are just 0s and 1s in memory, if you OR two integers, they will be ORed bit by bit, that is how OR works, regardless of the data type. – victor Nov 11 '15 at 23:29
  • @BrianOgden, didn't get. Do you want to output a binary string result of OR? – kyrylomyr Nov 11 '15 at 23:29
  • I updated my Question, my goal is to OR each bit and see if the result is all 1s or not, your solution is appropriate for my question. as @Andrew Shepherds, I think I will have to iterate through the bytes thought, I thought there might be a way to do binary1 | binary1 and see if it equals 1 or 0 but not its pretty clear there is not – Brian Ogden Nov 11 '15 at 23:35
  • @BrianOgden Here you go http://stackoverflow.com/questions/4854207/get-a-specific-bit-from-byte get specific bit from each byte and compare them. – M.kazem Akhgary Nov 11 '15 at 23:38
  • @BrianOgden, so, if the result of OR is "11111" then you want to return "true" (1), if any bit is "0" - then return "false" (0). Right? – kyrylomyr Nov 11 '15 at 23:44
  • Thanks @M.kazemAkhgary – Brian Ogden Nov 11 '15 at 23:51
  • 1
    Hey @kirmir I updated my question to show you what I am working on, please don't solve it for me, I just wanted you to see what I am trying to solve as it might interest you. – Brian Ogden Nov 12 '15 at 01:24
3

If you want to perform binary operations on the two equal-length arrays of bits, you can use Linq,

 var orResult = g[0].Zip(g[1], (b1, b2) => b1|b2).ToArray();

Note that bit operations are traditionally used in situations where performance is paramount. I would not expect this solution to perform well for bulk operations, but it might be good enough for your particular use case.


If your use case is to discover if any resulting bit is '0', then you can use linq's All method. This will stop and return false as soon as it encounters a zero.
 bool orResult = g[0].Zip(g[1], (b1, b2) => b1|b2).All(b => b != 0);
Andrew Shepherd
  • 44,254
  • 30
  • 139
  • 205
  • 1
    @Brigan Ogen - Your welcome. Using Linq is an interesting exercise, but if the quantity of bits is less than 32, I would recommend kimir's solution. – Andrew Shepherd Nov 12 '15 at 00:11
  • Yes, it was a tough decision, but I went with Kimir's solution, as it also had a little more "under the hood" exposure but thanks again for your solution, an elegant one and an interesting one to see in action, the powers of Linq ;) – Brian Ogden Nov 12 '15 at 00:16
1

For small values (that can be converted to an integer), you could use the following code. It converts the binary values to integers and then applies the or operator |. The result is then converted back to a binary string.

using System;

public class Program
{
    public static void Main()
    {
        var str1 = "10101";
        var str2 = "11100";
        var mask = str1.Replace('0','1');
        int one = Convert.ToInt32(str1, 2);
        int two = Convert.ToInt32(str2, 2);
        int maskbit = Convert.ToInt32(mask, 2);
        int result = (one | two)^maskbit;

        if (result==0){

            Console.WriteLine("All flags set");             
        }
        else            
        {
            Console.WriteLine("Not all flags set");             
        }   
    }
}
Alex
  • 21,273
  • 10
  • 61
  • 73
  • You can just use `Convert.ToString(result, 2);` there is no need to create your `BinaryString` method. – victor Nov 11 '15 at 23:40
  • Thanks for your answer, it was a good answer and nice to learn your solution, I went with Kimir's solution but it was not easy to pic. – Brian Ogden Nov 12 '15 at 00:16
0

The binary OR operator is not defined on type byte[], only on byte.

Binary | operators are predefined for the integral types and bool. For integral types, | computes the bitwise OR of its operands. For bool operands, | computes the logical OR of its operands; that is, the result is false if and only if both its operands are false.

https://msdn.microsoft.com/en-us/library/kxszd0kx.aspx

oɔɯǝɹ
  • 7,219
  • 7
  • 58
  • 69