Assigning values to array elements based on a lookup table
if (lookup.ContainsKey(transmitter))
        {
          var receiverLookup = lookup[transmitter];



This searches for the KeyValuePair twice. There's a more efficient approach:

        if (lookup.TryGetValue(transmitter, out var receiverLookup))





      var ungrouped = receivers.Except(blocksTracker).ToArray();

      foreach (var receiver in ungrouped)
      {
        blocks.Add(new Block(){Id = receiver, status = "red"});
        blocksTracker.Add(receiver);
      }



The ToArray() there is unnecessary: the enumerable can be left as a lazy enumerable because the only use is to iterate over it once.




          var intersection = receivers.Intersect(receiverLookup).ToArray();
          if (intersection.Length &gt; 0)
          {
             blocks.Add(new Block() { Id = transmitter, status = "yellow"});
             blocksTracker.Add(transmitter);
            foreach (var receiver in intersection)
            {
              blocks.Add(new Block(){Id = receiver, status = "yellow"});
              blocksTracker.Add(receiver);
            }
          } else  
          {
            blocks.Add(new Block(){Id = transmitter, status = "red"});
            blocksTracker.Add(transmitter);   
          }



This seems rather complicated. I think the whole thing could be simplified:

var transmittersPaired = new HashSet&lt;string&gt;();
var receiversPaired = new HashSet&lt;string&gt;();

foreach (var transmitter in transmitters)
{
    if (lookup.TryGetValue(transmitter, out var receiverLookup) &amp;&amp; receiverLookup.Any())
    {
        transmittersPaired.Add(transmitter);
        foreach (var receiver in receiverLookup)
        {
            receiversSeen.Add(receiver);
        }
    }
}

var blocks = new List&lt;Block&gt;();
foreach (var transmitter in transmitters)
{
    blocks.Add(new Block { Id = transmitter, status = transmittersPaired.Contains(transmitter) ? "yellow" : "red" });
}
foreach (var receiver in receivers)
{
    blocks.Add(new Block { Id = receiver, status = receiversPaired.Contains(receiver) ? "yellow" : "red" });
}


There's still some repeated code, which might be simplified in one of two ways. If there's a guarantee that the transmitters and receivers will never share IDs then transmittersPaired and receiversPaired could be merged into one set, and the foreach loops at the end could be merged into one loop over transmitters.Concat(receivers). Alternatively, a method could be factored out.