# What pattern will distinguish an element of a list from a list when used in a function?

In Mathematica several versions of a function can have the same name with a pattern distinguishing which version of the function should be used for which type of input. Here is a minimum working example of functions with different names and some test data. (I actually need to work with complicated modules the operation is not relevant. The data structure is relevant.).

ClearAll[fred1, fred2];
fred1[a_] := a[[3]];
fred2[a_] := a[[3, 2]];
(* Test data *)
a1 = {1, 2, 3, 4};
a2 = {{1, 10}, {2, 20}, {3, 30}};
b1 = {"s1", "s2", "s3", "s4"};
b2 = {{"s1", "s10"}, {"s2", "s20"}, {"s3", "s30"}, {"s4", "s40"} };


When the functions are applied to the test data they works correctly

(*  Test functions *)
fred1[a1]
fred2[a2]
fred1[b1]
fred2[b2]

3

30

"s3"

"s30"


Now if I want just one function name to do both of the operations given above I can try and distinguish both operations by using a pattern in the function definition. I can see a way to do this for numbers, but how do you do it for cases which are not numbers?

ClearAll[fred];
fred[a_ /; NumberQ[a[[1]]] ] := a[[3]];
fred[a_ /; NumberQ[a[[1, 1]]] ] := a[[3, 2]];

(* Test function *)
fred[a1]
fred[a2]
fred[b1]
fred[b2]


There are probably several ways of defining the pattern to make this work. Some sort of pattern that distinguishes an element of a list from a list. Is there a general way of doing this? Thanks

Clear["Global*"]

fred[a_?VectorQ] := a[[3]]

fred[a_?MatrixQ] := a[[3, 2]]

a1 = {1, 2, 3, 4};
a2 = {{1, 10}, {2, 20}, {3, 30}};
b1 = {"s1", "s2", "s3", "s4"};
b2 = {{"s1", "s10"}, {"s2", "s20"}, {"s3", "s30"}, {"s4", "s40"}};

fred /@ {a1, a2, b1, b2}

(* {3, 30, "s3", "s30"} *)


In your specific example this would do the job:

fred[a_ /; (NumberQ[a[[1]]] || StringQ[a[[1]]])] := a[[3]];
fred[a_ /; Head[a] == List && (NumberQ[a[[1, 1]]] || StringQ[a[[1, 1]]])] := a[[3,2]];


(I added the StringQ to the condition to get the same output as in your example)

This would fail for list like a1 = {{1}, {2}, {3}, {4}};, but you can also try with Depth` to check level of nested lists.

• That is helpful. However, a list can contain many types of elements with different types of heads. I don't want to have all sorts of heads questioned. Perhaps look for a head that is not a list? Depth might be useful.
– Hugh
Apr 20, 2021 at 18:17