amb
amb

Reputation: 113

Key-value lookup from a pair of lists in a makefile

In my makefile, I need to retrieve values from a value list given keys which match a key list. The lists are correctly ordered with respect to each other.

I have a recipe that works, but it uses a shell command to do the heavy lifting:

KEYS=key1 key2 key3 key4 key5
VALUES=val1 val2 val3 val4 val5

# keys to lookup, we want our results to be: val2 val4
LOOKUPS=key2 key4

define CMD
LOOKUPS=($(1)); \
KEYS=($(2)); \
VALUES=($(3)); \
for i in $${!LOOKUPS[@]}; do \
    for j in $${!KEYS[@]}; do \
        if [[ "$${LOOKUPS[$$i]}" ==  "$${KEYS[$$j]}" ]]; then \
            echo "$${VALUES[$$j]}"; \
        fi; \
    done; \
done
endef

RESULTS=$(shell $(call CMD,$(LOOKUPS),$(KEYS),$(VALUES)))
$(info RESULTS: $(RESULTS))

Is there a way of doing this without using the shell? Perhaps involving GMSL's pairmap function? Or a better shell based recipe?

Upvotes: 1

Views: 270

Answers (2)

Vroomfondel
Vroomfondel

Reputation: 2898

The GNUmake library gmtt has the function index-of which delivers the index of a string in a list. Without having it tested, the solution with ´gmtt´ would look like:

include gmtt.mk

KEYS=key1 key2 key3 key4 key5
VALUES=val1 val2 val3 val4 val5

# keys to lookup, we want our results to be: val2 val4
LOOKUPS=key2 key4

RESULTS := $(foreach s,$(LOOKUPS),$(word $(call index-of,$(s),neverakey $(KEYS)),$(VALUES)))

Notice that you have to elongate the list by one place (in front) because index-of is 0-based while word is 1-based (which was a deliberate design decision because going from 0-based to 1-based is much easier in ´make´ than the opposite)

Upvotes: 0

MadScientist
MadScientist

Reputation: 100936

I'm not sure about GMSL but you can cobble something together using GNU make's join function (solution untested):

KEYS=key1 key2 key3 key4 key5
VALUES=val1 val2 val3 val4 val5

# keys to lookup, we want our results to be: val2 val4
LOOKUPS=key2 key4

JOINED := $(join $(KEYS),$(addprefix :,$(VALUES)))

GETVAL = $(word 2,$(subst :, ,$(filter $1:%,$(JOINED))))

$(foreach K,$(LOOKUPS),$(info key $K = $(call GETVAL,$K)))

This assumes your keys and values don't contain the : character; if they do choose a different one.

Upvotes: 1

Related Questions