Finding which items have at least one common value with other items
For set-based operations like this it's better to use HashSet&lt;T&gt;.


  The HashSet&lt;T&gt; class provides high-performance set operations.


The items can easily be converted to ones containing HashSets. Then, the Overlaps method does the comparison:

var hashed = items
    .Select(i =&gt; new { Name = i.Name, Values = i.Values.ToHashSet() })
    .ToList();
var overlaps = hashed.Select(h1 =&gt; new
{
    h1.Name,
    Overlaps = hashed
        .Where(h2 =&gt; h2.Name != h1.Name &amp;&amp; h2.Values.Overlaps(h1.Values))
        .Select(h =&gt; h.Name)
});


Result:

A =&gt; B 
B =&gt; A,D 
C   
D =&gt; B 


Of course, if possible, it would be better to create items with HashSets at the outset.

EDIT

Triggered by your comment I did some benchmarking. I blew up your array a 1000 times, keeping unique names and then just measured both methods, using Linqpad:

var items = Enumerable.Range(1,1000).SelectMany(e =&gt;  new[]
{
    new { Name = "A" + e, Values = new [] { 20, 4, 5, 9, 3, 22 } },
    new { Name = "B" + e, Values = new [] { 10, 7, 9, 8, 42 } },
    new { Name = "C" + e, Values = new [] { 11, 103, 0 } },
    new { Name = "D" + e, Values = new [] { 7, 35, 42 } }
});

var sw = Stopwatch.StartNew();
var hashed = items.Select(i =&gt; new { Name = i.Name, Values = i.Values.ToHashSet() }).ToList();

sw.Elapsed.Dump();

var overlaps = hashed.Select(h1 =&gt; new
{
    h1.Name,
    Overlaps = hashed
        .Where(h2 =&gt; h2.Name != h1.Name &amp;&amp; h2.Values.Overlaps(h1.Values))
        .Select(h =&gt; h.Name).ToList()
}).ToList();
sw.Stop();
sw.Elapsed.Dump();

sw.Restart();
var tuples = items
    .SelectMany(x =&gt; x.Values, (x, y) =&gt; new { x.Name, Value = y })
    .ToList();

sw.Elapsed.Dump();
var result = tuples.Join(tuples,
           x =&gt; x.Value,
           x =&gt; x.Value,
           (x, y) =&gt; new { NameA = x.Name, NameB = y.Name })
    .Where(x =&gt; x.NameA != x.NameB)
    .Distinct()
    .GroupBy(x =&gt; x.NameA, x =&gt; x.NameB)
    .ToList();
sw.Stop();
sw.Elapsed.Dump();



The results:

00:00:00.0035664
00:00:02.0326684
00:00:00.0029370
00:00:06.3872002


As you see, the preparatory actions for both methods are done in 'no time', but the hashset-based method is considerably faster. Interestingly, if I blow up the arry 2000 times, the hashset-based method takes 7.7s and your method throws an OutOfMemoryException on my box.

Side note: if I don't make the names unique both methods are comparable. (On which I based my previous comment).