 <p>This is a job for <code>merge</code>:</p> <pre><code>KEYS &lt;- data.frame(A = AList, B = BList) merge(DATA, KEYS) # A B Value # 1 1 6 9 # 2 3 8 2 </code></pre> <hr> <p><strong>Edit</strong>: after the OP expressed his preference for a logical vector in the comments below, I would suggest one of the following.</p> <p>Use <code>merge</code>:</p> <pre><code>df.in.df &lt;- function(x, y) { common.names &lt;- intersect(names(x), names(y)) idx &lt;- seq_len(nrow(x)) x &lt;- x[common.names] y &lt;- y[common.names] x &lt;- transform(x, .row.idx = idx) idx %in% merge(x, y)$.row.idx } </code></pre> <p>or <code>interaction</code>:</p> <pre><code>df.in.df &lt;- function(x, y) { common.names &lt;- intersect(names(x), names(y)) interaction(x[common.names]) %in% interaction(y[common.names]) } </code></pre> <p>In both cases:</p> <pre><code>df.in.df(DATA, KEYS) # [1] TRUE FALSE TRUE FALSE FALSE FALSE </code></pre>