Following @aminrd's answer, you can also use np.isin instead of Python's in, which gives you the benefit of returning a boolean numpy array representing where the string hello appears.
import numpy as np
myarray = np.array(
[["hello", "salam", "bonjour"], ["a", "b", "c"], ["hello"]], dtype=object
)
ids = np.frompyfunc(lambda x: np.isin(x, "hello"), 1, 1)(myarray)
idxs = [(i, np.where(curr)[0][0]) for i, curr in enumerate(ids) if curr.any()]
Result:
>>> print(ids)
[array([ True, False, False]) array([False, False, False]) array([ True])]
>>> print(idxs)
[(0, 0), (2, 0)]
EDIT: If you want to avoid the explicit loop, you could pad the array with 0 (same as False) and then use numpy's broadcasting normally (this is necessary since ids becomes an object array with shape (3,))
>>> padded_ids = np.column_stack((itertools.zip_longest(*ids, fillvalue=0)))
>>> print(np.stack(np.where(padded_ids), axis=1))
[[0 0]
[2 0]]
Keep in mind padding methods usually have some kind of a loop somewhere, so I don't think you can totally get away from it.