Many programming languages provide convenient ways to look for a known value in a simple list of strings or numbers.

But what if the elements of the list are themselves compound records/objects/data-structures, and the search condition is more complex than a simple equality test?

Task[edit]
Write a function/method/etc. that can find the first element in a given list matching a given condition.

It should be as generic and reusable as possible.

(Of course if your programming language already provides such a feature, you can use that instead of recreating it.)

Then to demonstrate its functionality, create the data structure specified under #Data set, and perform on it the searches specified under #Test cases.

Data set
The data structure to be used contains the names and populations (in millions) of the 10 largest metropolitan areas in Africa, and looks as follows when represented in JSON:

[
  { "name": "Lagos",                "population": 21.0  },
  { "name": "Cairo",                "population": 15.2  },
  { "name": "Kinshasa-Brazzaville", "population": 11.3  },
  { "name": "Greater Johannesburg", "population":  7.55 },
  { "name": "Mogadishu",            "population":  5.85 },
  { "name": "Khartoum-Omdurman",    "population":  4.98 },
  { "name": "Dar Es Salaam",        "population":  4.7  },
  { "name": "Alexandria",           "population":  4.58 },
  { "name": "Abidjan",              "population":  4.4  },
  { "name": "Casablanca",           "population":  3.98 }
]
However, you shouldn't parse it from JSON, but rather represent it natively in your programming language.

 The top-level data structure should be an ordered collection (i.e. a list, array, vector, or similar).
 Each element in this list should be an associative collection that maps from keys to values (i.e. a struct, object, hash map, dictionary, or similar).
 Each of them has two entries: One string value with key "name", and one numeric value with key "population".
 You may rely on the list being sorted by population count, as long as you explain this to readers.


If any of that is impossible or unreasonable in your programming language, then feel free to deviate, as long as you explain your reasons in a comment above your solution.

Test cases


 Search

 Expected result


 Find the (zero-based) index of the first city in the list whose name is "Dar Es Salaam"

 6


 Find the name of the first city in this list whose population is less than 5 million

 Khartoum-Omdurman


 Find the population of the first city in this list whose name starts with the letter "A"

 4.58

Guidance
If your programming language supports higher-order programming, then the most elegant way to implement the requested functionality in a generic and reusable way, might be to write a function (maybe called "find_index" or similar), that takes two arguments:

 The list to search through.
 A function/lambda/closure (the so-called "predicate"), which will be applied in turn to each element in the list, and whose boolean return value defines whether that element matches the search requirement.
If this is not the approach which would be most natural or idiomatic in your language, explain why, and show what is.

Related tasks
 Search a list

	.model small
	.stack 1024
 
	.data
Africa     WORD LAGOS   ;"jagged" arrays are the bane of assembly programming, so store the string's pointer here instead.
	   WORD 2100H	;this is a bit cheaty but it's easier to store these as BCD whole numbers
	   WORD CAIRO
	   WORD 1520H
	   WORD KB
	   WORD 1130H
	   WORD GJ
	   WORD 0755H
	   WORD MOGADISHU
	   WORD 0585H
	   WORD KO
	   WORD 0498H
	   WORD DES
	   WORD 0470H
	   WORD ALEXANDRIA
	   WORD 0458H
	   WORD ABIDJAN
	   WORD 0440H
	   WORD CASABLANCA
	   WORD 0398H
 
LAGOS BYTE "Lagos",0
CAIRO BYTE "Cairo",0
KB BYTE "Kinshasa-Brazzaville",0
GJ BYTE "Greater Johannesburg",0
MOGADISHU BYTE "Mogadishu",0
KO BYTE "Khartoum-Omdurman",0
DES BYTE "Dar Es Salaam",0
ALEXANDRIA BYTE "Alexandria"
ABIDJAN BYTE "Abidjan",0
CASABLANCA BYTE "Casablanca",0
 
	.code
start:
 
	mov ax,@data		
	mov ds,ax			
 
	mov ax,@code		
	mov es,ax			
 
 
	cld	;String functions are set to auto-increment
 
	mov ax,2  ;clear screen by reloading the video mode we're in
	int 10h	  
 
	mov si,offset Africa
 
;test 1: find the index of the city whose name is Dar-Es-Salaam
 
	mov di,offset DES ;it's easier to test the equality of two pointers than of two strings.
	mov cx,10	  ;ten cities to check
	mov bx,0	  ;our counter
 
test_case_1:
	lodsw
	cmp ax,di		;compare to the pointer of Dar-Es_Salaam
	je done_test_case_1
	add si,2	        ;we know populations aren't going to match so skip them
	inc bx			;increment the counter
	loop test_case_1
 
done_test_case_1:
	mov al,bl
	call Printhex	        ;print the index of Dar-Es-Salaam
	call Newline		;print CRLF
 
 
;test 2: print the name of the first city whose population is less than 5 million.
	mov si,offset Africa
	mov cx,10
 
 
test_case_2:
	lodsw		;we know that the struct goes city:pop so skip the first word.
	lodsw
	cmp ax,0500h
	jae skip
		sub si,4		;point SI back to the city name
		mov si,[ds:si]
		call PrintString
		call NewLine
		jmp done_test_case_2
 
skip:
	loop test_case_2
done_test_case_2:
 
 
;test 3: find the population of the first city in this list whose name starts with A
	mov si,offset Africa
	mov cx,10
 
test_case_3:
	lodsw
	push si
		mov si,ax
		lodsb
		cmp al,'A'
	pop si
	je FoundIt		;popping SI won't affect the compare result.
 
	add si,2		;skip population
	loop test_case_3
 
 
 
 
ExitDOS:
	mov ax,4C00h		;return to dos
	int 21h
 
FoundIt:
	lodsw
	mov dx,ax
	mov al,dh
	call Printhex_NoLeadingZeroes
	mov al,'.'             ;we're faking floating point for simplicity's sake
	call PrintChar
	mov al,dl
	call PrintHex
	jmp ExitDos
 
end start