TensorFlow
Tensors
Python
Machine Learning
Deep Learning

Apply function for every pair of elements in two Tensors in Tensorflow

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

When people say they want to apply a function to every pair of elements from two TensorFlow tensors, they usually mean one of two different operations. Either they want elementwise pairing, where x[i] is combined with y[i], or they want the full Cartesian product, where every value in x is combined with every value in y. The correct TensorFlow pattern depends on which one you actually need.

Case 1: Elementwise Pairing

If the tensors already have compatible shapes and you want to combine matching positions, write the function with TensorFlow ops and let TensorFlow apply it elementwise.

python
1import tensorflow as tf
2
3x = tf.constant([1.0, 2.0, 3.0])
4y = tf.constant([10.0, 20.0, 30.0])
5
6def pair_fn(a, b):
7    return tf.square(a - b) + a * b
8
9result = pair_fn(x, y)
10print(result.numpy())

This is the preferred approach because it stays vectorized and uses TensorFlow kernels efficiently.

Case 2: All Pairs with Broadcasting

If you need every element of x combined with every element of y, use broadcasting by expanding one dimension on each side.

python
1import tensorflow as tf
2
3x = tf.constant([1.0, 2.0, 3.0])
4y = tf.constant([10.0, 20.0])
5
6def pair_fn(a, b):
7    return a + b
8
9all_pairs = pair_fn(x[:, tf.newaxis], y[tf.newaxis, :])
10print(all_pairs.numpy())

Output:

text
[[11. 21.]
 [12. 22.]
 [13. 23.]]

The shape logic is the key:

  • 'x[:, tf.newaxis] changes shape from (3,) to (3, 1)'
  • 'y[tf.newaxis, :] changes shape from (2,) to (1, 2)'
  • TensorFlow broadcasts them to (3, 2)

That final matrix contains one result for every pair (x_i, y_j).

Why Broadcasting Is Usually Better Than tf.map_fn

TensorFlow provides tf.map_fn, but it is rarely the best first answer for pairwise numeric work. If your function can be written as normal tensor math, broadcasting is usually shorter, clearer, and faster.

For example, pairwise absolute differences are one line:

python
1x = tf.constant([1.0, 4.0, 7.0])
2y = tf.constant([2.0, 5.0])
3
4pairwise_diff = tf.abs(x[:, tf.newaxis] - y[tf.newaxis, :])
5print(pairwise_diff.numpy())

Use tf.map_fn only when the logic is genuinely map-shaped and not naturally expressed as tensor broadcasting.

Extending the Pattern to Rows

The same idea works for higher-dimensional tensors. Suppose x has shape (n, d) and y has shape (m, d), and you want one value per pair of rows.

python
1import tensorflow as tf
2
3x = tf.constant([[1.0, 2.0], [3.0, 4.0]])
4y = tf.constant([[1.0, 1.0], [0.0, 0.0], [2.0, 2.0]])
5
6pairwise_sqdist = tf.reduce_sum(
7    tf.square(x[:, tf.newaxis, :] - y[tf.newaxis, :, :]),
8    axis=-1,
9)
10
11print(pairwise_sqdist.numpy())

This produces an (n, m) matrix of pairwise squared distances.

Watch the Output Size

Broadcasting is elegant, but all-pairs computations can get large quickly. If x has length 10000 and y has length 10000, the result already has one hundred million pair entries.

In that situation, you may need to:

  • batch the computation
  • reduce intermediate tensors earlier
  • use a specialized operation if TensorFlow provides one

So the best answer is not only “use broadcasting,” but “use broadcasting when the resulting tensor size is realistic.”

Common Pitfalls

The most common mistake is not clarifying whether “every pair” means elementwise pairing or the full Cartesian product. Those are different computations and produce different shapes.

Another mistake is using Python loops around tensors. That throws away vectorization and often makes the code slower and harder to optimize.

A third issue is expanding dimensions in the wrong place and silently producing the wrong result shape. Always print or inspect the shapes during development.

Summary

  • Use normal TensorFlow ops for elementwise pairing
  • Use broadcasting for the full all-pairs combination
  • 'tf.map_fn is usually not the best first choice for simple pairwise tensor math'
  • Always verify shapes so you know whether you built zipped pairs or a Cartesian product
  • Be careful with memory when the all-pairs result becomes large

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design