Search a list of records: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|zkl}}: add "update" template due to the new task description)
 
(147 intermediate revisions by 55 users not shown)
Line 1: Line 1:
{{Task|List processing}}
{{draft task|Array search}}


Many programming languages provide convenient ways to look for a known value in a simple list of strings or list of numbers.<br>
Many programming languages provide convenient ways to look for a known value in a simple list of strings or numbers.<br>
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?
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 heading}}
{{task heading}}


Write a function/method/etc. that can find the first element in a given list of records/objects matching a given condition.<br>
Write a function/method/etc. that can find the first element in a given list matching a given condition.<br>
It should be as generic and reusable as possible.<br>
It should be as generic and reusable as possible.<br>
(Of course if your programming language already provides such a feature, you can use that instead of recreating it.)
(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 below, and perform the following searches on it:
Then to demonstrate its functionality, create the data structure specified under [[#Data set]], and perform on it the searches specified under [[#Test cases]].

# Find the (zero-based) '''index''' of the first city in the list whose '''name is "<tt>Dar Es Salaam</tt>"'''.
# Find the '''name''' of the first city in this list whose '''population is less than 5 million'''.
# Find the '''population''' of the first city in this list whose '''name starts with the letter "<tt>A</tt>"'''.


{{task heading|Data set}}
{{task heading|Data set}}


The data structure to be used contains the names and populations of the 10 largest metropolitan areas in Africa, and looks as follows when represented in JSON:
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:


<syntaxhighlight lang="javascript">[
<lang JavaScript>[
{ "name": "Lagos", "population": 21.0 },
{ "name": "Lagos", "population": 21.0 },
{ "name": "Cairo", "population": 15.2 },
{ "name": "Cairo", "population": 15.2 },
Line 31: Line 27:
{ "name": "Abidjan", "population": 4.4 },
{ "name": "Abidjan", "population": 4.4 },
{ "name": "Casablanca", "population": 3.98 }
{ "name": "Casablanca", "population": 3.98 }
]</lang>
]</syntaxhighlight>


However, you shouldn't parse it from JSON, but rather represent it natively in your programming language.
However, you shouldn't parse it from JSON, but rather represent it natively in your programming language.
Line 38: Line 34:
* 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 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 "<tt>name</tt>", and one numeric value with key "<tt>population</tt>".
* Each of them has two entries: One string value with key "<tt>name</tt>", and one numeric value with key "<tt>population</tt>".
* You may rely on the list being sorted by population count, as long as you explain this to readers.


<br>
If any of that is impossible or unreasonable in your programming language, then feel free to deviate, as long as you explain it in a comment above your solution.
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.

{{task heading|Test cases}}

{| class="wikitable"
|-
! Search
! Expected result
|-
| Find the (zero-based) '''index''' of the first city in the list whose '''name is "<tt>Dar Es Salaam</tt>"'''
| <tt>6</tt>
|-
| Find the '''name''' of the first city in this list whose '''population is less than 5 million'''
| <tt>Khartoum-Omdurman</tt>
|-
| Find the '''population''' of the first city in this list whose '''name starts with the letter "<tt>A</tt>"'''
| <tt>4.58</tt>
|}


{{task heading|Guidance}}
{{task heading|Guidance}}
Line 49: Line 64:
If this is not the approach which would be most natural or idiomatic in your language, explain why, and show what is.
If this is not the approach which would be most natural or idiomatic in your language, explain why, and show what is.


{{task heading|See also}}
{{task heading|Related tasks}}


* [[Search a list]]
* [[Search a list]]
Line 55: Line 70:
<hr>
<hr>


=={{header|ALGOL 68}}==
=={{header|11l}}==
<syntaxhighlight lang="11l">T City
String name
Float population


F (name, population)
{{update|ALGOL 68|
.name = name
* The second test-case has been clarified to no longer require sort.
.population = population
* A third test-case has been added.
}}


V cities = [
Note the data for the task is already sorted in descending order of population so the sort shown here isn't strictly necessary, however in general we couldn't rely on that.
City(‘Lagos’, 21),
<lang algol68># Algol 68 doesn't have generic array searches but we can easily provide #
City(‘Cairo’, 15.2),
City(‘Kinshasa-Brazzaville’, 11.3),
City(‘Greater Johannesburg’, 7.55),
City(‘Mogadishu’, 5.85),
City(‘Khartoum-Omdurman’, 4.98),
City(‘Dar Es Salaam’, 4.7),
City(‘Alexandria’, 4.58),
City(‘Abidjan’, 4.4),
City(‘Casablanca’, 3.98)
]

F first_index(cities, condition)
L(city) cities
I condition(city)
R L.index

F first(cities, condition)
L(city) cities
I condition(city)
R city

print(first_index(cities, city -> city.name == ‘Dar Es Salaam’))
print(first(cities, city -> city.population < 5.0).name)
print(first(cities, city -> city.name[0] == ‘A’).population)</syntaxhighlight>

{{out}}
<pre>
6
Khartoum-Omdurman
4.58
</pre>

=={{header|8086 Assembly}}==
===Task-Specific Solution===
This solution answers the questions as asked, and only those asked - it won't answer an arbitrary question regarding the list. All I/O subroutines that involve printing the results were left unimplemented to keep this entry brief.

<syntaxhighlight lang="asm"> .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</syntaxhighlight>

{{out}}
<pre>06
Khartoum-Omdurman
4.58</pre>

=={{header|8th}}==
8th uses JSON as its native data representation, so using it is quite natural:
<syntaxhighlight lang="forth">[
{ "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 }
] var, cities-raw

"Index of first occurrence of 'Dar Es Salaam': " .
"Dar Es Salaam" >r cities-raw @
(
"name" m:@ r@ s:= if
drop . cr ;;
then
2drop
) a:each drop rdrop

"The name of the first city in this list whose population is less than 5 million: " .
5 >r cities-raw @
(
nip
"population" m:@ r@ n:< if
"name" m:@ . cr break
then
drop
) a:each drop rdrop

"The population of the first city in this list whose name starts with the letter \"A\": " .
'A >r cities-raw @
(
nip
"name" m:@ 0 s:@ r@ n:= if
drop "population" m:@ . cr break
then
2drop
) a:each drop rdrop

bye</syntaxhighlight>
{{out}}
<pre>
Index of first occurrence of 'Dar Es Salaam': 6
The name of the first city in this list whose population is less than 5 million: Khartoum-Omdurman
The population of the first city in this list whose name starts with the letter "A": 4.58000
</pre>

=={{header|Action!}}==
{{libheader|Action! Tool Kit}}
<syntaxhighlight lang="action!">INCLUDE "D2:REAL.ACT" ;from the Action! Tool Kit

DEFINE PTR="CARD"
DEFINE ENTRY_SIZE="4"
DEFINE STX="$8E"
DEFINE STA="$8D"
DEFINE JSR="$20"
DEFINE RTS="$60"

TYPE City=[
CARD
name, ;CHAR ARRAY
population] ;REAL POINTER

BYTE ARRAY cities(100)
BYTE count=[0]

CHAR ARRAY nameParam ;param for name predicate
REAL popParam ;param for population predicate
CHAR letterParam ;param for letter predicate
CITY POINTER c ;city used in predicates and actions
BYTE index ;index of city used in index action

PTR FUNC GetItemAddr(BYTE index)
PTR addr

addr=cities+index*ENTRY_SIZE
RETURN (addr)

PROC Append(CHAR ARRAY n REAL POINTER p)
City POINTER dst

dst=GetItemAddr(count)
dst.name=n
dst.population=p
count==+1
RETURN

PROC InitData()
REAL lg,ca,ki,gr,mo,kh,da,al,ab,cs

ValR("21.0",lg) ValR("15.2",ca)
ValR("11.3",ki) ValR("7.53",gr)
ValR("5.85",mo) ValR("4.98",kh)
ValR("4.7",da) ValR("4.58",al)
ValR("4.4",ab) ValR("3.98",cs)

Append("Lagos",lg)
Append("Cairo",ca)
Append("Kinshasa-Brazzaville",ki)
Append("Greater Johannesburg",gr)
Append("Mogadishu",mo)
Append("Khartoum-Omdurman",kh)
Append("Dar Es Salaam",da)
Append("Alexandria",al)
Append("Abidjan",ab)
Append("Casablanca",cs)
RETURN

BYTE FUNC NameEquals()
RETURN (SCompare(c.name,nameParam)+1)

BYTE FUNC PopulationLess()
REAL diff
BYTE ARRAY x

RealSub(popParam,c.population,diff)
x=diff
IF (x(0)&$80)=$00 THEN
RETURN (1)
FI
RETURN (0)

BYTE FUNC FirstLetter()
CHAR ARRAY n

n=c.name
IF n(0)>=1 AND n(1)=letterParam THEN
RETURN (1)
FI
RETURN (0)

;jump addr is stored in X and A registers
BYTE FUNC Predicate=*(PTR jumpAddr)
[STX Predicate+8
STA Predicate+7
JSR $00 $00
RTS]

PROC PrintIndex()
PrintF("index=%I%E",index)
RETURN

PROC PrintName()
PrintF("name=%S%E",c.name)
RETURN

PROC PrintPopulation()
Print("population=")
PrintRE(c.population)
RETURN

;jump addr is stored in X and A registers
PROC Action=*(PTR jumpAddr)
[STX Action+8
STA Action+7
JSR $00 $00
RTS]

PROC Find(PTR predicateFun,actionFun)
FOR index=0 TO count-1
DO
c=GetItemAddr(index)
IF Predicate(predicateFun) THEN
Action(actionFun)
EXIT
FI
OD
RETURN

PROC Main()
Put(125) PutE() ;clear screen
InitData()

nameParam="Dar Es Salaam"
Find(NameEquals,PrintIndex)

ValR("5.0",popParam)
Find(PopulationLess,PrintName)

letterParam='A
Find(FirstLetter,PrintPopulation)
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Search_a_list_of_records.png Screenshot from Atari 8-bit computer]
<pre>
index=6
name=Khartoum-Omdurman
population=4.58
</pre>

=={{header|Ada}}==

This solution in inspired by how the <code>Ada.Containers</code> child packages work. Usually a <code>Cursor</code> contains two accesses: one to the container and one to the element. Since we want to get the index of the element as well, the index was stored instead.

{{works with|Ada|Ada|2005}}

<syntaxhighlight lang="ada">with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO;

procedure Search_A_List_Of_Records
is
function "+"(input : in String) return Unbounded_String renames To_Unbounded_String;
function "+"(input : in Unbounded_String) return String renames To_String;

type City is record
name : Unbounded_String;
population : Float;
end record;

type City_Array is array(Positive range <>) of City;
type City_Array_Access is access City_Array;

type Cursor is record
container : City_Array_Access;
index : Natural;
end record;

function Element(C : in Cursor) return City is
begin
if C.container = null or C.index = 0 then
raise Constraint_Error with "No element.";
end if;

return C.container.all(C.index);
end Element;

function Index_0(C : in Cursor) return Natural is
begin
if C.container = null or C.index = 0 then
raise Constraint_Error with "No element.";
end if;

return C.index - C.container.all'First;
end Index_0;

function Find
(container : in City_Array;
check : not null access function(Element : in City) return Boolean)
return Cursor
is
begin
for I in container'Range loop
if check.all(container(I)) then
return (new City_Array'(container), I);
end if;
end loop;
return (null, 0);
end;

function Dar_Es_Salaam(Element : in City) return Boolean is
begin
return Element.name = "Dar Es Salaam";
end Dar_Es_Salaam;

function Less_Than_Five_Million(Element : in City) return Boolean is
begin
return Element.population < 5.0;
end Less_Than_Five_Million;

function Starts_With_A(Item : in City) return Boolean is
begin
return Element(Item.name, 1) = 'A';
end Starts_With_A;

cities : constant City_Array :=
((+"Lagos", 21.0),
(+"Cairo", 15.2),
(+"Kinshasa-Brazzaville", 11.3),
(+"Greater Johannesburg", 7.55),
(+"Mogadishu", 5.85),
(+"Khartoum-Omdurman", 4.98),
(+"Dar Es Salaam", 4.7 ),
(+"Alexandria", 4.58),
(+"Abidjan", 4.4 ),
(+"Casablanca", 3.98));
begin
Ada.Text_IO.Put_Line(Index_0(Find(cities, Dar_Es_Salaam'Access))'Img);
Ada.Text_IO.Put_Line(+Element(Find(cities, Less_Than_Five_Million'Access)).name);
Ada.Text_IO.Put_Line(Element(Find(cities, Starts_With_A'Access)).population'Img);
end Search_A_List_Of_Records;</syntaxhighlight>
{{out}}
<pre> 6
Khartoum-Omdurman
4.58000E+00
</pre>

=={{header|ALGOL 68}}==
<syntaxhighlight lang="algol68"># Algol 68 doesn't have generic array searches but we can easily provide #
# type specific ones #
# type specific ones #


Line 101: Line 582:
result
result
END # FIND # ;
END # FIND # ;

# convenience operator to determine whether a STRING starts with a particular character #
# returns TRUE if s starts with c, FALSE otherwise #
PRIO STARTSWITH = 9;
OP STARTSWITH = ( STRING s, CHAR c )BOOL:
IF LWB s > UPB s THEN FALSE # empty string #
ELSE s[ LWB s ] = c
FI # STARTSWITH # ;


# find the 0-based index of Dar Es Salaam #
# find the 0-based index of Dar Es Salaam #
Line 111: Line 600:
);
);


# operator to sort the cities with a specified comparator #
# find the first city with population under 5M #
# NB - this assumes there is one - would get a subscript bound error if there isn't #
PRIO SORT = 1;
OP SORT = ( REF[]CITYINFO array, PROC( REF CITYINFO, REF CITYINFO )BOOL less than )REF[]CITYINFO:
print( ( name OF cities[ cities FIND ( ( REF CITYINFO city )BOOL: population in millions OF city < 5.0 ) ]
, " has a population under 5M"
BEGIN
, newline
HEAP[ LWB array : UPB array ]CITYINFO sorted := array;
)
# bubble sort - replace with more efficient algorithm for "real" use... #
);
FOR end pos FROM UPB sorted - 1 BY -1 TO LWB sorted
WHILE
BOOL swapped := FALSE;
FOR pos FROM LWB sorted TO end pos DO
IF NOT less than( sorted[ pos ], sorted[ pos + 1 ] )
THEN
CITYINFO t := sorted[ pos ];
sorted[ pos ] := sorted[ pos + 1 ];
sorted[ pos + 1 ] := t;
swapped := TRUE
FI
OD;
swapped
DO SKIP OD;
sorted
END # SORT # ;


# find the city with the highest population under 5M #
# find the population of the first city whose name starts with "A" #
# NB - this assumes there is one - would get a subscript range error if there isn't #
# NB - this assumes there is one - would get a subscript bound error if there isn't #
print( ( name OF cities[ ( cities SORT ( ( REF CITYINFO a, b )BOOL: population in millions OF a > population in millions OF b )
print( ( "The population of a city named ""A..."" is: "
) FIND ( ( REF CITYINFO city )BOOL: population in millions OF city < 5.0 )
, fixed( population in millions OF cities[ cities FIND ( ( REF CITYINFO city )BOOL: name OF city STARTSWITH "A" ) ], 0, 2 )
]
, newline
)
, " has the maximum population under 5M"
, newline
)
</syntaxhighlight>
)
)</lang>
{{out}}
{{out}}
<pre>
<pre>
index of Dar Es Salaam (from 0): 6
index of Dar Es Salaam (from 0): 6
Khartoum-Omdurman has the maximum population under 5M
Khartoum-Omdurman has a population under 5M
The population of a city named "A..." is: 4.58
</pre>
</pre>


=={{header|C}}==
=={{header|AppleScript}}==


{{Trans|JavaScript}}
{{update|C|

* The second test-case has been clarified to no longer require sort.
<syntaxhighlight lang="applescript">-- RECORDS
* A third test-case has been added.

}}
property lstCities : [¬
{|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}]


-- SEARCHES

-- nameIsDar :: Record -> Bool
on nameIsDar(rec)
|name| of rec = "Dar Es Salaam"
end nameIsDar

-- popBelow :: Record -> Bool
on popBelow5M(rec)
population of rec < 5
end popBelow5M

-- nameBeginsWith :: Record -> Bool
on nameBeginsWithA(rec)
text 1 of |name| of rec = "A"
end nameBeginsWithA


-- TEST
on run
return {¬
findIndex(nameIsDar, lstCities), ¬
¬
|name| of find(popBelow5M, lstCities), ¬
¬
population of find(nameBeginsWithA, lstCities)}
end run




-- GENERIC FUNCTIONS

-- find :: (a -> Bool) -> [a] -> Maybe a
on find(f, xs)
tell mReturn(f)
set lng to length of xs
repeat with i from 1 to lng
if lambda(item i of xs) then return item i of xs
end repeat
return missing value
end tell
end find

-- findIndex :: (a -> Bool) -> [a] -> Maybe Int
on findIndex(f, xs)
tell mReturn(f)
set lng to length of xs
repeat with i from 1 to lng
if lambda(item i of xs) then return i
end repeat
return missing value
end tell
end findIndex

-- Lift 2nd class handler function into 1st class script wrapper
-- mReturn :: Handler -> Script
on mReturn(f)
if class of f is script then
f
else
script
property lambda : f
end script
end if
end mReturn</syntaxhighlight>

{{Out}}
<syntaxhighlight lang="applescript">{6, "Khartoum-Omdurman", 4.58}</syntaxhighlight>

=== AppleScriptObjectiveC ===

While vanilla AppleScript doesn't provide filters for its own lists and records (and, by the way, has never officially supported square-bracket lists like the one used in the script above), its extension AppleScriptObjectiveC ''can'' filter the equivalent Foundation classes. So bridging between the classes may occasionally be useful. For efficiency, one would try to avoid repeatedly bridging the same objects.

<syntaxhighlight lang="applescript">use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"

-- Return the zero-based index of the first dictionary in an array which matches a given criterion or criteria.
on indexOfFirstDictionaryInArray:theArray |whose|:predicateText
set filter to current application's class "NSPredicate"'s predicateWithFormat:(predicateText)
set filteredArray to theArray's filteredArrayUsingPredicate:(filter)
if ((count filteredArray) > 0) then
return (theArray's indexOfObjectIdenticalTo:(filteredArray's firstObject())) as integer
else
return missing value -- No match.
end if
end indexOfFirstDictionaryInArray:|whose|:

on run
local listOfRecords, arrayOfDictionaries, result1, result2, result3
set listOfRecords to {¬
{|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}}
set arrayOfDictionaries to current application's class "NSArray"'s arrayWithArray:(listOfRecords)
set result1 to my indexOfFirstDictionaryInArray:arrayOfDictionaries |whose|:"name == 'Dar Es Salaam'"
set result2 to my indexOfFirstDictionaryInArray:arrayOfDictionaries |whose|:"population < 5"
if (result2 is not missing value) then set result2 to |name| of item (result2 + 1) of listOfRecords
set result3 to my indexOfFirstDictionaryInArray:arrayOfDictionaries |whose|:"name BEGINSWITH 'A'"
if (result3 is not missing value) then set result3 to population of item (result3 + 1) of listOfRecords
return {result1, result2, result3} --> {6, "Khartoum-Omdurman", 4.58}
end run</syntaxhighlight>

=={{header|Arturo}}==

<syntaxhighlight lang="rebol">; by @Krenium

define :city [name population][]

records: map [
["Lagos" 21.0]
["Cairo" 15.2]
["Kinshasa-Brazzaville" 11.3]
["Greater Johannesburg" 7.55]
["Mogadishu" 5.85]
["Khartoum-Omdurman" 4.98]
["Dar Es Salaam" 4.7]
["Alexandria" 4.58]
["Abidjan" 4.4]
["Casablanca" 3.98]
] => [to :city &]

find: function [block f][
loop.with: 'i block 'elt [
if f elt -> return @[elt i]
]
return false
]

; Print the index of the first city named Dar Es Salaam.
print last find records $[c][equal? c\name "Dar Es Salaam"]

; Print the name of the first city with under 5 million people.
print get first find records $[c][less? c\population 5] 'name

; Print the population of the first city starting with 'A'.
print get first find records $[c][equal? first c\name `A`] 'population</syntaxhighlight>

{{out}}

<pre>6
Khartoum-Omdurman
4.58</pre>

=={{header|BASIC}}==
==={{header|Commodore BASIC}}===
C= BASIC has no associative data structure, so this just uses a two-dimensional array. It is written to accept a dynamically-sized list of cities and populations, with an empty-string sentinel indicating the end of the list.
It also uses a form of pseudo-higher-order programming: the search function uses the query function `FNQ`, which is redefined by the caller to match the desired criteria for each test.

Note that in text mode (upper/lowercase), BASIC keywords are only recognized in lowercase.
<syntaxhighlight lang="gwbasic">100 nc=0
110 read n$
120 if n$="" then 160
130 read p$
140 nc=nc+1
150 goto 110
160 restore
170 dim ci$(nc-1,1)
180 for i=0 to nc-1
190 : for j=0 to 1
200 : read ci$(i,j)
210 : next j
220 next i
230 :
240 print chr$(14);:rem text mode
250 print: print "Test 1. name='Dar Es Salaam':"
260 rem search uses query function fnq
270 def fnq(i) = ci$(i,0) = "Dar Es Salaam"
280 gosub 500
290 if i<0 then print " None found.":goto 310
300 print " Index="i"."
310 print: print "Test 2. population < 5M:"
320 def fnq(i) = val(ci$(i,1)) < 5
330 gosub 500
340 if i<0 then print " None found.":goto 360
350 print " Name="ci$(i,0)"."
360 print: print "Test 3. name like 'A%':"
370 def fnq(i) = left$(ci$(i,0),1)="A"
380 gosub 500
390 if i<0 then print " None found.":goto 410
400 print " Population="ci$(i,1)"."
410 end
420 :
500 for i=0 to nc-1
510 : if fnq(i) then return
520 next i
530 i=-1
540 return
550 :
560 data "Lagos", 21.0
570 data "Cairo", 15.2
580 data "Kinshasa-Brazzaville", 11.3
590 data "Greater Johannesburg", 7.55
600 data "Mogadishu", 5.85
610 data "Khartoum-Omdurman", 4.98
620 data "Dar Es Salaam", 4.7
630 data "Alexandria", 4.58
640 data "Abidjan", 4.4
650 data "Casablanca", 3.98
660 data ""</syntaxhighlight>

{{Out}}
<pre>ready.
run

Test 1. name='Dar Es Salaam':
Index= 6 .

Test 2. population < 5M:
Name=Khartoum-Omdurman.

Test 3. name like 'A%':
Population=4.58.

ready.</pre>

==={{header|FreeBASIC}}===
<syntaxhighlight lang="freebasic">Type Registro
name As String*20
population As Double
End Type
Dim cities(1 To 10) As Registro => { _
("Lagos",21.0 ), ("Cairo", 15.2 ), ("Kinshasa-Brazzaville", 11.3 ), _
("Greater Johannesburg", 7.55), ("Mogadishu", 5.85), ("Khartoum-Omdurman", 4.98), _
("Dar Es Salaam", 4.7 ), ("Alexandria", 4.58), ("Abidjan", 4.4 ), ("Casablanca", 3.98)}

Dim As Byte n
For n = 1 To Ubound(cities)
If cities(n).name = "Dar Es Salaam" Then Print n-1
Next n

For n = 1 To Ubound(cities)
If cities(n).population < 5.00 Then Print cities(n).name : Exit For
Next n

For n = 1 To Ubound(cities)
If Left(cities(n).name,1) = "A" Then Print cities(n).population : Exit For
Next n
Sleep</syntaxhighlight>
{{out}}
<pre> 6
Khartoum-Omdurman
4.58</pre>

==={{header|QBasic}}===
{{works with|QBasic|1.1}}
{{works with|QuickBasic|4.5}}
<syntaxhighlight lang="qbasic">DIM cities$(10, 10)
cities$(1, 1) = "Lagos": cities$(1, 2) = "21.0"
cities$(2, 1) = "Cairo": cities$(2, 2) = "15.2"
cities$(3, 1) = "Kinshasa-Brazzaville": cities$(3, 2) = "11.3"
cities$(4, 1) = "Greater Johannesburg": cities$(4, 2) = "7.55"
cities$(5, 1) = "Mogadishu": cities$(5, 2) = "5.85"
cities$(6, 1) = "Khartoum-Omdurman": cities$(6, 2) = "4.98"
cities$(7, 1) = "Dar Es Salaam": cities$(7, 2) = "4.7"
cities$(8, 1) = "Alexandria": cities$(8, 2) = "4.58"
cities$(9, 1) = "Abidjan": cities$(9, 2) = "4.4"
cities$(10, 1) = "Casablanca": cities$(10, 2) = "3.98"

FOR n = 1 TO UBOUND(cities$)
IF cities$(n, 1) = "Dar Es Salaam" THEN PRINT n - 1
NEXT n

FOR n = 1 TO UBOUND(cities$)
IF VAL(cities$(n, 2)) < 5! THEN PRINT cities$(n, 1): EXIT FOR
NEXT n

FOR n = 1 TO UBOUND(cities$)
IF LEFT$(cities$(n, 1), 1) = "A" THEN PRINT cities$(n, 2): EXIT FOR
NEXT n
</syntaxhighlight>
{{out}}
<pre>Same as FreeBASIC entry.</pre>

==={{header|True BASIC}}===
<syntaxhighlight lang="qbasic">DIM cities$(10, 10)
LET cities$(1, 1) = "Lagos"
LET cities$(1, 2) = "21.0"
LET cities$(2, 1) = "Cairo"
LET cities$(2, 2) = "15.2"
LET cities$(3, 1) = "Kinshasa-Brazzaville"
LET cities$(3, 2) = "11.3"
LET cities$(4, 1) = "Greater Johannesburg"
LET cities$(4, 2) = "7.55"
LET cities$(5, 1) = "Mogadishu"
LET cities$(5, 2) = "5.85"
LET cities$(6, 1) = "Khartoum-Omdurman"
LET cities$(6, 2) = "4.98"
LET cities$(7, 1) = "Dar Es Salaam"
LET cities$(7, 2) = "4.7"
LET cities$(8, 1) = "Alexandria"
LET cities$(8, 2) = "4.58"
LET cities$(9, 1) = "Abidjan"
LET cities$(9, 2) = "4.4"
LET cities$(10, 1) = "Casablanca"
LET cities$(10, 2) = "3.98"

FOR n = 1 TO UBOUND(cities$,1)
IF cities$(n, 1) = "Dar Es Salaam" THEN PRINT n-1
NEXT n

FOR n = 1 TO UBOUND(cities$,1)
IF VAL(cities$(n, 2)) < 5 THEN
PRINT cities$(n, 1)
EXIT FOR
END IF
NEXT n

FOR n = 1 TO UBOUND(cities$,1)
IF (cities$(n, 1))[1:1] = "A" THEN
PRINT cities$(n, 2)
EXIT FOR
END IF
NEXT n
END</syntaxhighlight>
{{out}}
<pre>Same as FreeBASIC entry.</pre>

==={{header|Yabasic}}===
<syntaxhighlight lang="yabasic">dim cities$(9, 9)
cities$(0, 0) = "Lagos" : cities$(0, 1) = "21.0"
cities$(1, 0) = "Cairo" : cities$(1, 1) = "15.2"
cities$(2, 0) = "Kinshasa-Brazzaville" : cities$(2, 1) = "11.3"
cities$(3, 0) = "Greater Johannesburg" : cities$(3, 1) = "7.55"
cities$(4, 0) = "Mogadishu" : cities$(4, 1) = "5.85"
cities$(5, 0) = "Khartoum-Omdurman" : cities$(5, 1) = "4.98"
cities$(6, 0) = "Dar Es Salaam" : cities$(6, 1) = "4.7"
cities$(7, 0) = "Alexandria" : cities$(7, 1) = "4.58"
cities$(8, 0) = "Abidjan" : cities$(8, 1) = "4.4"
cities$(9, 0) = "Casablanca" : cities$(9, 1) = "3.98"

for n = 1 to arraysize(cities$(), 1)
if cities$(n, 0) = "Dar Es Salaam" print n
next n

for n = 1 to arraysize(cities$(), 1)
if val(cities$(n, 1)) < 5 then print cities$(n, 0): break: fi
next n

for n = 1 to arraysize(cities$(), 1)
if left$(cities$(n, 0), 1) = "A" then print cities$(n, 1): break: fi
next n</syntaxhighlight>
{{out}}
<pre>Same as FreeBASIC entry.</pre>

=={{header|C}}==


This solution makes use of the 'bsearch' and 'lfind' library functions. Note: 'lfind' is available only on Posix systems, and is found in the 'search.h' header.
This solution makes use of the 'bsearch' and 'lfind' library functions. Note: 'lfind' is available only on Posix systems, and is found in the 'search.h' header. However it is also part of the Ming C Compiler for Windows.
<syntaxhighlight lang="c">
<lang c>
#include <stdint.h> /* intptr_t */
#include <stdint.h> /* intptr_t */
#include <stdio.h>
#include <stdio.h>
Line 163: Line 1,011:
#include <string.h>
#include <string.h>
#include <search.h> /* lfind */
#include <search.h> /* lfind */

#define LEN(x) (sizeof(x) / sizeof(x[0]))
#define LEN(x) (sizeof(x) / sizeof(x[0]))

struct cd {
struct cd {
char *name;
char *name;
double population;
double population;
};
};

/* Return -1 if name could not be found */
/* Return -1 if name could not be found */
int search_get_index_by_name(const char *name, const struct cd *data, const size_t data_length,
int search_get_index_by_name(const char *name, const struct cd *data, const size_t data_length,
Line 178: Line 1,026:
struct cd *match = bsearch(&key, data, data_length,
struct cd *match = bsearch(&key, data, data_length,
sizeof(struct cd), cmp_func);
sizeof(struct cd), cmp_func);

if (match == NULL)
if (match == NULL)
return -1;
return -1;
else
else
return ((intptr_t) match - (intptr_t) data) / sizeof(struct cd);
return ((intptr_t) match - (intptr_t) data) / sizeof(struct cd);
}
/* Return -1 if no matching record can be found */
double search_get_pop_by_name(const char *name, const struct cd *data, size_t data_length,
int (*cmp_func)(const void *, const void *))
{
struct cd key = { (char *) name, 0 };
struct cd *match = lfind(&key, data, &data_length,
sizeof(struct cd), cmp_func);
if (match == NULL)
return -1;
else
return match->population;
}
}


Line 192: Line 1,054:
struct cd *match = lfind(&key, data, &data_length,
struct cd *match = lfind(&key, data, &data_length,
sizeof(struct cd), cmp_func);
sizeof(struct cd), cmp_func);

if (match == NULL)
if (match == NULL)
return NULL;
return NULL;
Line 199: Line 1,061:
}
}


int cd_nameChar_cmp(const void *a, const void *b)
{
struct cd *aa = (struct cd *) a;
struct cd *bb = (struct cd *) b;
int i,len = strlen(aa->name);

for(i=0;i<len;i++)
if(bb->name[i]!=aa->name[i])
return -1;
return 0;
}
int cd_name_cmp(const void *a, const void *b)
int cd_name_cmp(const void *a, const void *b)
{
{
Line 205: Line 1,080:
return strcmp(bb->name, aa->name);
return strcmp(bb->name, aa->name);
}
}

int cd_pop_cmp(const void *a, const void *b)
int cd_pop_cmp(const void *a, const void *b)
{
{
Line 212: Line 1,087:
return bb->population >= aa->population;
return bb->population >= aa->population;
}
}

int main(void)
int main(void)
{
{
Line 227: Line 1,102:
{ "Casablanca", 3.98 }
{ "Casablanca", 3.98 }
};
};

const size_t citydata_length = LEN(citydata);
const size_t citydata_length = LEN(citydata);

printf("%d\n", search_get_index_by_name("Dar Es Salaam", citydata, citydata_length, cd_name_cmp));
printf("%d\n", search_get_index_by_name("Dar Es Salaam", citydata, citydata_length, cd_name_cmp));
printf("%s\n", search_get_pop_threshold(5, citydata, citydata_length, cd_pop_cmp));
printf("%s\n", search_get_pop_threshold(5, citydata, citydata_length, cd_pop_cmp));
printf("%d\n", search_get_index_by_name("Dar Salaam", citydata, citydata_length, cd_name_cmp));
printf("%lf\n", search_get_pop_by_name("A", citydata, citydata_length, cd_nameChar_cmp));
printf("%s\n", search_get_pop_threshold(2, citydata, citydata_length, cd_pop_cmp) ?: "(null)");
return 0;
return 0;
}
}
</syntaxhighlight>
</lang>


Output
<pre>
6
Khartoum-Omdurman
4.580000
</pre>

=={{header|C sharp|C#}}==
<syntaxhighlight lang="csharp">using System;
using System.Collections.Generic;

namespace RosettaSearchListofRecords
{
class Program
{
static void Main(string[] args)
{
var dataset = new List<Dictionary<string, object>>() {
new Dictionary<string, object> {{ "name" , "Lagos"}, {"population", 21.0 }},
new Dictionary<string, object> {{ "name" , "Cairo"}, {"population", 15.2 }},
new Dictionary<string, object> {{ "name" , "Kinshasa-Brazzaville"}, {"population", 11.3 }},
new Dictionary<string, object> {{ "name" , "Greater Johannesburg"}, {"population", 7.55 }},
new Dictionary<string, object> {{ "name" , "Mogadishu"}, {"population", 5.85 }},
new Dictionary<string, object> {{ "name" , "Khartoum-Omdurman"}, {"population", 4.98 }},
new Dictionary<string, object> {{ "name" , "Dar Es Salaam"}, {"population", 4.7 }},
new Dictionary<string, object> {{ "name" , "Alexandria"}, {"population", 4.58 }},
new Dictionary<string, object> {{ "name" , "Abidjan"}, {"population", 4.4 }},
new Dictionary<string, object> {{ "name" , "Casablanca"}, {"population", 3.98 }}
};

// Find the (zero-based) index of the first city in the list whose name is "Dar Es Salaam"
var index = dataset.FindIndex(x => ((string)x["name"]) == "Dar Es Salaam");
Console.WriteLine(index);

// Find the name of the first city in this list whose population is less than 5 million
var name = (string)dataset.Find(x => (double)x["population"] < 5.0)["name"];
Console.WriteLine(name);

// Find the population of the first city in this list whose name starts with the letter "A"
var aNamePopulation = (double)dataset.Find(x => ((string)x["name"]).StartsWith("A"))["population"];
Console.WriteLine(aNamePopulation);
}
}
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
6
6
Khartoum-Omdurman
Khartoum-Omdurman
4.58
-1
(null)
</pre>
</pre>

=={{header|C++}}==

<tt>std::find_if</tt> accepts a lambda as predicate.

<syntaxhighlight lang="cpp">#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

struct city {
std::string name;
float population;
};

int main()
{
std::vector<city> cities = {
{ "Lagos", 21 },
{ "Cairo", 15.2 },
{ "Kinshasa-Brazzaville", 11.3 },
{ "Greater Johannesburg", 7.55 },
{ "Mogadishu", 5.85 },
{ "Khartoum-Omdurman", 4.98 },
{ "Dar Es Salaam", 4.7 },
{ "Alexandria", 4.58 },
{ "Abidjan", 4.4 },
{ "Casablanca", 3.98 },
};
auto i1 = std::find_if( cities.begin(), cities.end(),
[](city c){ return c.name == "Dar Es Salaam"; } );
if (i1 != cities.end()) {
std::cout << i1 - cities.begin() << "\n";
}
auto i2 = std::find_if( cities.begin(), cities.end(),
[](city c){ return c.population < 5.0; } );
if (i2 != cities.end()) {
std::cout << i2->name << "\n";
}
auto i3 = std::find_if( cities.begin(), cities.end(),
[](city c){ return c.name.length() > 0 && c.name[0] == 'A'; } );
if (i3 != cities.end()) {
std::cout << i3->population << "\n";
}
}</syntaxhighlight>

{{out}}
<pre>
6
Khartoum-Omdurman
4.58
</pre>


=={{header|Clojure}}==
In order to not rely on the input ordering of the data records, this example adds an "idx" value to the records, for purposes of being able to report the answer to the queries which rely on the original ordering. The data records are then re-sorted to be ordered by city name. This helps to make it clear that the query relying on sort-by-population is properly handled in the query itself.

<syntaxhighlight lang="clojure">(def records [{:idx 8, :name "Abidjan", :population 4.4}
{:idx 7, :name "Alexandria", :population 4.58}
{:idx 1, :name "Cairo", :population 15.2}
{:idx 9, :name "Casablanca", :population 3.98}
{:idx 6, :name "Dar Es Salaam", :population 4.7}
{:idx 3, :name "Greater Johannesburg", :population 7.55}
{:idx 5, :name "Khartoum-Omdurman", :population 4.98}
{:idx 2, :name "Kinshasa-Brazzaville", :population 11.3}
{:idx 0, :name "Lagos", :population 21.0}
{:idx 4, :name "Mogadishu", :population 5.85}])

(defn city->idx [recs city]
(-> (some #(when (= city (:name %)) %)
recs)
:idx))

(defn rec-with-max-population-below-n [recs limit]
(->> (sort-by :population > recs)
(drop-while (fn [r] (>= (:population r) limit)))
first))

(defn most-populous-city-below-n [recs limit]
(:name (rec-with-max-population-below-n recs limit)))</syntaxhighlight>

{{out}}
<pre>
(city->idx records "Dar Es Salaam") ; 6

(most-populous-city-below-n records 5.0) ; "Khartoum-Omdurman"

(->> (sort-by :idx records)
(drop-while #(not (clojure.string/starts-with? (:name %) "A")))
first
:population) ; 4.58
</pre>

=={{header|Common Lisp}}==
<syntaxhighlight lang="lisp">(defstruct city
(name nil :type string)
(population nil :type number))

(defparameter *cities*
(list (make-city :name "Lagos" :population 21.0)
(make-city :name "Cairo" :population 15.2)
(make-city :name "Kinshasa-Brazzaville" :population 11.3)
(make-city :name "Greater Johannesburg" :population 7.55)
(make-city :name "Mogadishu" :population 5.85)
(make-city :name "Khartoum-Omdurman" :population 4.98)
(make-city :name "Dar Es Salaam" :population 4.7)
(make-city :name "Alexandria" :population 4.58)
(make-city :name "Abidjan" :population 4.4)
(make-city :name "Casablanca" :population 3.98)))

(defun main ()
(let ((answer1 (position "Dar Es Salaam" *cities* :key #'city-name :test #'string=))
(answer2 (city-name (find-if (lambda (population) (< population 5))
*cities* :key #'city-population)))
(answer3 (city-population (find-if (lambda (name) (char= (char name 0) #\A))
*cities* :key #'city-name))))
(format t "Answer 1: ~A~%" answer1)
(format t "Answer 2: ~A~%" answer2)
(format t "Answer 3: ~A~%" answer3)))</syntaxhighlight>
{{out}}
<pre>Answer 1: 6
Answer 2: Khartoum-Omdurman
Answer 3: 4.58</pre>


=={{header|EchoLisp}}==
=={{header|EchoLisp}}==
Line 254: Line 1,298:


We demonstrate the '''vector-search''' primitive, which takes as input a vector, and a predicate.
We demonstrate the '''vector-search''' primitive, which takes as input a vector, and a predicate.
<lang scheme>
<syntaxhighlight lang="scheme">
(require 'struct)
(require 'struct)
(require 'json)
(require 'json)
Line 288: Line 1,332:
(city-pop -666) → (-666 . not-found)
(city-pop -666) → (-666 . not-found)
(city-index "alexandra") → #f
(city-index "alexandra") → #f
</syntaxhighlight>
</lang>


=={{header|J}}==
=={{header|Elena}}==
ELENA 6.x :
<syntaxhighlight lang="elena">import extensions;
import system'routines;
public program()
{
var dataset := new object[]
{
new { Name = "Lagos"; Population = 21.0r; },
new { Name = "Cairo"; Population = 15.2r; },
new { Name = "Kinshasa-Brazzaville"; Population = 11.3r; },
new { Name = "Greater Johannesburg"; Population = 7.55r; },
new { Name = "Mogadishu"; Population = 5.85r; },
new { Name = "Khartoum-Omdurman"; Population = 4.98r; },
new { Name = "Dar Es Salaam"; Population = 4.7r; },
new { Name = "Alexandria"; Population = 4.58r; },
new { Name = "Abidjan"; Population = 4.4r; },
new { Name = "Casablanca"; Population = 3.98r; }
};
var index := dataset.selectBy::(r => r.Name).toArray().indexOfElement("Dar Es Salaam");
console.printLine(index);
var name := dataset.filterBy::(c => c.Population < 5.0r).toArray().FirstMember.Name;
console.printLine(name);
var namePopulation := dataset.filterBy::(c => c.Name.startingWith("A")).toArray().FirstMember.Population;
console.printLine(namePopulation)
}</syntaxhighlight>
{{out}}
<pre>
6
Khartoum-Omdurman
4.58
</pre>


=={{header|Elixir}}==
{{update|J|
<syntaxhighlight lang="elixir">cities = [
* The stuff about searching simple lists of strings or numbers, doesn't belong here. Maybe move it to [[Search a list]].
[name: "Lagos", population: 21.0 ],
* A third search condition test-case has been added.
[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]
]


IO.puts Enum.find_index(cities, fn city -> city[:name] == "Dar Es Salaam" end)
J supports several "searching" primitives.
IO.puts Enum.find(cities, fn city -> city[:population] < 5.0 end)[:name]
IO.puts Enum.find(cities, fn city -> String.first(city[:name])=="A" end)[:population]</syntaxhighlight>


{{out}}
<code>i.</code> finds the indices of the things being looked for (with 0 being the first index). Nonmatches get a result of 1+largest valid index.
<pre>
6
Khartoum-Omdurman
4.58
</pre>


=={{header|Factor}}==
<lang j> 1 2 3 4 5 6 7 8 9 i. 2 3 5 60
For our associative structure, we use the tuple: an object composed of named slots, each holding a value which can be accessed using automatically-generated accessors. Factor is built around combinators (Factor's word for higher-order functions), so completing the task as requested is idiomatic. <code>find</code> is an existing combinator that takes a sequence and a predicate quotation (quotation being Factor's word for anonymous function) and returns the first element of the sequence for which the predicate quotation yields <code>t</code>.
1 2 4 9
(;:'one two three four five six seven eight nine') i. ;:'two three five sixty'
1 2 4 9</lang>


Not only does <code>find</code> return the element, but also the index, which allows us to use <code>find</code> for all of the required tasks. Since Factor is a stack-based concatenative language, multiple return values are elegant to use. We can simply <code>drop</code> the sequence element on the top of the data stack if we are only interested in the index, or we can <code>nip</code> the index if we are only interested in the sequence element on the top of the stack.
<code>e.</code> finds whether items are members of a set, returning a bitmask to select the members:
<syntaxhighlight lang="factor">USING: accessors io kernel math prettyprint sequences ;
IN: rosetta-code.search-list


TUPLE: city name pop ;
<lang j> 1 2 3 4 5 6 7 8 9 e. 2 3 5 60
0 1 1 0 1 0 0 0 0
(;:'one two three four five six seven eight nine') e. ;:'two three five sixty'
0 1 1 0 1 0 0 0 0</lang>


CONSTANT: data {
<code>I.</code> finds indices, but performs a binary search (which requires that the list being searched is sorted). This can be useful for finding non-exact matches (the index of the next value is returned for non-exact matches).
T{ city f "Lagos" 21.0 }
T{ city f "Cairo" 15.2 }
T{ city f "Kinshasa-Brazzaville" 11.3 }
T{ city f "Greater Johannesburg" 7.55 }
T{ city f "Mogadishu" 5.85 }
T{ city f "Khartoum-Omdurman" 4.98 }
T{ city f "Dar Es Salaam" 4.7 }
T{ city f "Alexandria" 4.58 }
T{ city f "Abidjan" 4.4 }
T{ city f "Casablanca" 3.98 }
}


! Print the index of the first city named Dar Es Salaam.
<lang j> 1 2 3 4 5 6 7 8 9 I. 2 3 5 60 6.66
data [ name>> "Dar Es Salaam" = ] find drop .
1 2 4 9 6

(;:'eight five four nine one seven six three two') I. ;:'two three five sixty'
! Print the name of the first city with under 5 million people.
8 7 1 7</lang>
data [ pop>> 5 < ] find nip name>> print

! Print the population of the first city starting with 'A'.
data [ name>> first CHAR: A = ] find nip pop>> .</syntaxhighlight>
{{out}}
<pre>
6
Khartoum-Omdurman
4.58
</pre>

=={{header|Fortran}}==
In order to employ a compound data aggregate such as CITY with components CITY.NAME and CITY.POPULATION, F90 is required. Earlier, one would have employed a collection of separate arrays with similar names, such as CNAME and CPOP. This may still be desirable when array parameters from a data aggregate will be passed via copy-in and copy-out instead of by reference. An alternative declaration would be to have the components of the aggregate use the array aspect, as in <code>REAL POPULATION(10)</code> This would also avoid wasting storage due to multiple padding forced by any alignment requirements, as when a floating-point variable has to be aligned to a storage boundary. Otherwise, with "packed" storage, extra code required to access unaligned items consumes extra storage and of course, extra time. But the specification calls for multiplicity of the pairs. By contrast, pl/i offers "floating indexing" whereby <code>CITY(i).NAME</code> ''and'' <code>CITY.NAME(i)</code> would be acceptable usages for ''either'' form of declaration, thus concealing the issue.

As for the names, one must choose a maximum size for the city name, and 28 seems a perfect choice, even for names in Madagascar. Later fortran offers facilities for character variables "fitted to size", at the cost of extra indirection.

Fortran does not offer a "pass-by-name" facility, whereby the test function for the searches could be specified in the manner of [[Jensen's_Device]], something like <code>FINDFIRST(I,CITY(I).NAME .EQ. "Dar Es Salaam")</code> and <code>FINDFIRST(I,CITY(I).POPULATION < 5)</code> in the form of boolean expressions evaluated in the calling environment, so one must devise a suitable procedure, and because the two components NAME and POPULATION have different types, the parameter matching protocol requires two different procedures. Via additional F90 syntax it is possible to define a "generic" routine with a single name that, when invoked, will in fact invoke the appropriate specific routine, however in this example one test is for equality, and the other is for "less than" so the commonality is weak. One could instead define two boolean functions (one each for the two types of test, say NAMEISEQUAL and POPULATIONISLESS) and pass the appropriate function as a parameter to a more general FINDFIRST routine, but this is both messy and restrictive: two functions to be defined separately and with FINDFIRST, all will only accept a type CITYSTAT as parameters. And as the TARGET parameter is of two different types, there can't be one FINDFIRST routine anyway.

Instead, two search functions. Using the function's name as a variable within the function could not be relied on prior to F90: some compilers would disallow it and in other cases odd results might be produced, so a local variable would have to be used. These functions turn out to be general in the sense that they're not limited to a type of CITYSTAT. Instead, FIRSTMATCH searches an array of texts, and FIRSTLESS an array of floating-point numbers - they could be applied to any such arrays. But sometimes at a cost. They are not prepared to deal with arrays having a "stride" other than one, such as the CITY.NAME entries, whose successive elements are not in successive storage locations. Instead, the compiler generates code to copy the desired elements from the CITY aggregate into a temporary variable having that arrangement, and passes that to the routine by reference. One could use the special declaration <code>INTENT(IN)</code> for read-only activities, and that will at least abate the copy-back, but for small items and only ten at that, this overhead can be ignored; otherwise in-line code would be required for each search. On the other hand, it does allow the special usage <code>CITY.NAME(1:1)</code> to search only the first character of each name.

Although F90 allows an array to be defined with a lower bound other than the default of one, this requires such a non-default lower bound to be specified in every declaration, which is tiresome, and leads to confusion over counting. Still, to suit the requirement, the index found for Dar Es Salaam is reduced by one. Returning a value of zero for "not found" is helpful (-1 would be good too, but this can't be an unsigned integer) and it is often useful to have an actual element zero with a dummy entry, such as <code>CITYSTAT("--No such city!",3E33)</code> so that a WRITE statement need not be prefaced by a test so as to avoid an index-out-of-bounds error. The dummy population value, if printed, will likely overflow its format code and fill its space with asterisks in the standard behaviour. More modern systems include the reading or writing of the special mnemonic "NaN" for "Not a Number" but this mnemonic is not recognised in fortran source itself so something like <code>PARAMETER (NaN = Z'FFFFFFFFFFFFFFFF')</code> would be needed if preferred - though readers may not recgnise that mnemonic either. With such a dummy-element scheme, the searches would be specified by <code>FIRSTMATCH(CITY(1:).NAME,"Dar Es Salaam")</code> to signify that the zero'th element was not involved. Alternatively, the special entry could follow the "live" entries and "not found" would be an index value of eleven, there being ten entries in this example. If entries are to be added or removed, this becomes tiresome, but it does mean that there need no longer be an assignment of the "not found" value after the DO-loop's search, because that will be the value of the index variable on exit - though some argue that no such exit value should be relied upon. Coherent organisation is required for this! Incidentally, 0 (zero) in the source continuation field is treated as a space (meaning no continuation), thus the letter o instead: O would be asking for misreading.

The specification mentions an ordered list: here, the items are indeed ordered in storage (as first, second, etc) but ordering more usefully refers to the values of the components. The example is presented in reducing order of population. More generally, the storage order might be arbitrary, and one would use indices, arrays such as XCNAME which would list the entries in the order of their names, and XCPOP their populations. These arrays would each be produced by an indexed sort process that would not move the data about, and so long as entries were not frequently altered (requiring re-sorting) these indices could be used for searching. <code>IT = FIRSTMATCH(CITY(XCNAME).NAME,"Dar Es Salaam")</code> would search the city names in alphabetical order rather than storage order and <code>IT</code> would be its position in XCNAME so that <code>CITY(XCNAME(IT)).POPULATION</code> would give the city's population. However, the "not found" result would be troublesome if not tested for. If zero was the value for that, arranging that XCNAME(0) was zero would help, however an often useful usage for XCNAME(0) is for it to contain the number of elements in its list.

Such arrays involve the ability to access an individual city's information at random, simply by specifying the index into the CITY array, however the given problem requires only sequential access. In such a case, the storage for the city elements could be formed as a linked-list which would be followed sequentially. Even so, random access can be regained via an array such as XCNAME, which now would hold the storage address of the corresponding CITY element. And as ever, how long is a piece of string? Here, ten.

If the data were stored as records in a disc file, a record zero won't exist and so appropriate testing for "not found" will be required. For this example however there is no attempt either to prepare a suitable "not found" entry nor to test and evade such a misfortune. The test data employed do not provoke such errors... <syntaxhighlight lang="fortran"> MODULE SEMPERNOVIS !Keep it together.
TYPE CITYSTAT !Define a compound data type.
CHARACTER*28 NAME !Long enough?
REAL POPULATION !Accurate enough.
END TYPE CITYSTAT !Just two parts, but different types.
TYPE(CITYSTAT) CITY(10) !Righto, I'll have some.
DATA CITY/ !Supply the example's data.
1 CITYSTAT("Lagos", 21.0 ),
2 CITYSTAT("Cairo", 15.2 ),
3 CITYSTAT("Kinshasa-Brazzaville",11.3 ),
4 CITYSTAT("Greater Johannesburg", 7.55),
5 CITYSTAT("Mogadishu", 5.85),
6 CITYSTAT("Khartoum-Omdurman", 4.98),
7 CITYSTAT("Dar Es Salaam", 4.7 ),
8 CITYSTAT("Alexandria", 4.58),
9 CITYSTAT("Abidjan", 4.4 ),
o CITYSTAT("Casablanca", 3.98)/
CONTAINS
INTEGER FUNCTION FIRSTMATCH(TEXT,TARGET) !First matching.
CHARACTER*(*) TEXT(:) !An array of texts.
CHARACTER*(*) TARGET !The text to look for.
DO FIRSTMATCH = 1,UBOUND(TEXT,DIM = 1) !Scan the array from the start.
IF (TEXT(FIRSTMATCH) .EQ. TARGET) RETURN !An exact match? Ignoring trailing spaces.
END DO !Try the next.
FIRSTMATCH = 0 !No match. Oh dear.
END FUNCTION FIRSTMATCH

INTEGER FUNCTION FIRSTLESS(VAL,TARGET) !First matching.
REAL VAL(:) !An array of values.
REAL TARGET !The value to look for.
DO FIRSTLESS = 1,UBOUND(VAL,DIM = 1) !Step through the array from the start.
IF (VAL(FIRSTLESS) .LT. TARGET) RETURN !Suitable?
END DO !Try the next.
FIRSTLESS = 0 !No match. Oh dear.
END FUNCTION FIRSTLESS
END MODULE SEMPERNOVIS

PROGRAM POKE
USE SEMPERNOVIS !Ex Africa, ...
CHARACTER*(*) BLAH !Save on some typing.
PARAMETER (BLAH = "The first city in the list whose ") !But also, for layout.

WRITE (6,1) BLAH,FIRSTMATCH(CITY.NAME,"Dar Es Salaam") - 1 !My array starts with one.
1 FORMAT (A,"name is Dar Es Salaam, counting with zero, is #",I0)

WRITE (6,2) BLAH,CITY(FIRSTLESS(CITY.POPULATION,5.0)).NAME
2 FORMAT (A,"population is less than 5 is ",A)

WRITE (6,3) BLAH,CITY(FIRSTMATCH(CITY.NAME(1:1),"A")).POPULATION
3 FORMAT (A,"whose name starts with A has population",F5.2)
END</syntaxhighlight>

The words NAME and TARGET can have special usages in F90, but fortran has ''no'' reserved words so these names can be put to ordinary use. Alas, the syntax highlighter does not recognise their non-special use and gives them colour. One could fuss further over the layout of the output, but here it is:
<pre>
The first city in the list whose name is Dar Es Salaam, counting with zero, is #6
The first city in the list whose population is less than 5 is Khartoum-Omdurman
The first city in the list whose whose name starts with 'A' has population 4.58
</pre>

=={{header|Go}}==
'''Basic solution:'''
<syntaxhighlight lang="go">package main

import (
"fmt"
"strings"
)

type element struct {
name string
population float64
}

var list = []element{
{"Lagos", 21},
{"Cairo", 15.2},
{"Kinshasa-Brazzaville", 11.3},
{"Greater Johannesburg", 7.55},
{"Mogadishu", 5.85},
{"Khartoum-Omdurman", 4.98},
{"Dar Es Salaam", 4.7},
{"Alexandria", 4.58},
{"Abidjan", 4.4},
{"Casablanca", 3.98},
}

func find(cond func(*element) bool) int {
for i := range list {
if cond(&list[i]) {
return i
}
}
return -1
}

func main() {
fmt.Println(find(func(e *element) bool {
return e.name == "Dar Es Salaam"
}))

i := find(func(e *element) bool {
return e.population < 5
})
if i < 0 {
fmt.Println("*** not found ***")
} else {
fmt.Println(list[i].name)
}

i = find(func(e *element) bool {
return strings.HasPrefix(e.name, "A")
})
if i < 0 {
fmt.Println("*** not found ***")
} else {
fmt.Println(list[i].population)
}
}</syntaxhighlight>
{{out}}
<pre>
6
Khartoum-Omdurman
4.58
</pre>

'''Data conversion solution:'''

The prohibition on parsing JSON is unreasonable in any language. The alternative to parsing by computer is parsing manually, reformatting data with human fingers on a keyboard. It's okay for ten lines of test data but would be unreasonable in any real application. But let's say than in real life you have a pointy-haired boss that decrees that no JSON parsing will be done &mdash; even though he has contracted a vendor that supplies JSON only. You would write a data converter that quietly converts data outside the application.

First, a package to define the data structure needed. This package will be imported by both the data conversion tool and the application.
<syntaxhighlight lang="go">package datadef

type Element struct {
Name string
Population float64
}

type List []Element</syntaxhighlight>

Then the data conversion tool. This program reads JSON from stdin and generates the Go code of a package "data" containing an equivalent Go literal.
<syntaxhighlight lang="go">package main

import (
"encoding/json"
"fmt"
"go/build"
"log"
"os"
"path/filepath"

"datadef"
)

func main() {
var l datadef.List
if err := json.NewDecoder(os.Stdin).Decode(&l); err != nil {
log.Fatal(err)
}
pp := filepath.Join(filepath.SplitList(build.Default.GOPATH)[0], "src/data")
f, err := os.Create(filepath.Join(pp, "data.go"))
if err != nil {
log.Fatal(err)
}
fmt.Fprintln(f, `package data
import "datadef"
var List = datadef.List {`)
for i, e := range l {
fmt.Fprintf(f, " %d: {%q, %g},\n", i, e.Name, e.Population)
}
fmt.Fprintln(f, "}")
}</syntaxhighlight>
{{out}}
<syntaxhighlight lang="go">package data
import "datadef"
var List = datadef.List {
0: {"Lagos", 21},
1: {"Cairo", 15.2},
2: {"Kinshasa-Brazzaville", 11.3},
3: {"Greater Johannesburg", 7.55},
4: {"Mogadishu", 5.85},
5: {"Khartoum-Omdurman", 4.98},
6: {"Dar Es Salaam", 4.7},
7: {"Alexandria", 4.58},
8: {"Abidjan", 4.4},
9: {"Casablanca", 3.98},
}</syntaxhighlight>

The desired program imports the generated package containing the converted data. Program and imported data are JSON-free.
<syntaxhighlight lang="go">package main

import (
"fmt"
"strings"

"data"
"datadef"
)

func find(cond func(*datadef.Element) bool) int {
for i := range data.List {
if cond(&data.List[i]) {
return i
}
}
return -1
}

func main() {
i := find(func(e *datadef.Element) bool {
return e.Name == "Dar Es Salaam"
})
if i < 0 {
fmt.Println("*** not found ***")
} else {
fmt.Println(i)
}

i = find(func(e *datadef.Element) bool {
return e.Population < 5
})
if i < 0 {
fmt.Println("*** not found ***")
} else {
fmt.Println(data.List[i].Name)
}

i = find(func(e *datadef.Element) bool {
return strings.HasPrefix(e.Name, "A")
})
if i < 0 {
fmt.Println("*** not found ***")
} else {
fmt.Println(data.List[i].Population)
}
}</syntaxhighlight>
Output same as basic solution.

'''Solution using sorted population count:'''

The population ordering is useful only for queries against population and so cannot be used, at least not in any simple way, by the general find function shown above. The sort package of the Go standard library however contains a function for making general queries against an ordered list. This solution shows how the population query can be done with this function.

<syntaxhighlight lang="go">package main

import (
"fmt"
"sort"

"data"
)

func main() {
if !sort.SliceIsSorted(data.List, func(i, j int) bool {
return data.List[i].Population > data.List[j].Population
}) {
panic("data not sorted by decreasing population")
}

i := sort.Search(len(data.List), func(i int) bool {
return data.List[i].Population < 5
})
if i == len(data.List) {
fmt.Println("*** not found ***")
} else {
fmt.Println(data.List[i].Name)
}
}</syntaxhighlight>
{{out}}
<pre>
Khartoum-Omdurman
</pre>

'''sort.Search for the other queries:'''

The same sort.Search function is general enough to be used for the other two queries of the task as long as appropriate indexes are constructed. sort.Search is interesting because it is in the standard library and is much like the function required by the task, being generalized to take a function as an argument. It does not completely meet task requirements though because it works on a single ordering that must already exist or already be computed. A function that would analyze a general query, use available orderings when possible, and fall back on linear search otherwise is surely beyond the task scope.

<syntaxhighlight lang="go">package main

import (
"fmt"
"sort"
"strings"

"data"
)

func main() {
nx := make([]int, len(data.List))
for i := range nx {
nx[i] = i
}
sort.Slice(nx, func(i, j int) bool {
return data.List[nx[i]].Name < data.List[nx[j]].Name
})

i := sort.Search(len(nx), func(i int) bool {
return data.List[nx[i]].Name >= "Dar Es Salaam"
})
if i == len(nx) || data.List[nx[i]].Name != "Dar Es Salaam" {
fmt.Println("*** not found ***")
} else {
fmt.Println(nx[i])
}

for i := range nx {
nx[i] = i
}
sort.SliceStable(nx, func(i, j int) bool {
return data.List[nx[i]].Name[0] < data.List[nx[j]].Name[0]
})

i = sort.Search(len(nx), func(i int) bool {
return data.List[nx[i]].Name >= "A"
})
if i == len(nx) || !strings.HasPrefix(data.List[nx[i]].Name, "A") {
fmt.Println("*** not found ***")
} else {
fmt.Println(data.List[nx[i]].Population)
}
}</syntaxhighlight>
{{out}}
<pre>
6
4.58
</pre>

=={{header|Haskell}}==

<syntaxhighlight lang="haskell">import Data.List (findIndex, find)

data City = City
{ name :: String
, population :: Float
} deriving (Read, Show)

-- CITY PROPERTIES ------------------------------------------------------------
cityName :: City -> String
cityName (City x _) = x

cityPop :: City -> Float
cityPop (City _ x) = x

mbCityName :: Maybe City -> Maybe String
mbCityName (Just x) = Just (cityName x)
mbCityName _ = Nothing

mbCityPop :: Maybe City -> Maybe Float
mbCityPop (Just x) = Just (cityPop x)
mbCityPop _ = Nothing

-- EXAMPLES -------------------------------------------------------------------
mets :: [City]
mets =
[ City
{ name = "Lagos"
, population = 21.0
}
, City
{ name = "Cairo"
, population = 15.2
}
, City
{ name = "Kinshasa-Brazzaville"
, population = 11.3
}
, City
{ name = "Greater Johannesburg"
, population = 7.55
}
, City
{ name = "Mogadishu"
, population = 5.85
}
, City
{ name = "Khartoum-Omdurman"
, population = 4.98
}
, City
{ name = "Dar Es Salaam"
, population = 4.7
}
, City
{ name = "Alexandria"
, population = 4.58
}
, City
{ name = "Abidjan"
, population = 4.4
}
, City
{ name = "Casablanca"
, population = 3.98
}
]

-- TEST -----------------------------------------------------------------------
main :: IO ()
main = do
mbPrint $ findIndex (("Dar Es Salaam" ==) . cityName) mets
mbPrint $ mbCityName $ find ((< 5.0) . cityPop) mets
mbPrint $ mbCityPop $ find (("A" ==) . take 1 . cityName) mets

mbPrint
:: Show a
=> Maybe a -> IO ()
mbPrint (Just x) = print x
mbPrint x = print x</syntaxhighlight>

{{Out}}
<pre>6
"Khartoum-Omdurman"
4.58</pre>

=={{header|J}}==


And, for the tabular example in the current task description, here is the data we will be using:
To represent the data in the task description, we will be using a tabular format as follows:


<lang J>colnumeric=: 0&".&.>@{`[`]}
<syntaxhighlight lang="j">colnumeric=: 0&".&.>@{`[`]}


data=: 1 colnumeric |: fixcsv 0 :0
data=: 1 colnumeric |: fixcsv 0 :0
Line 335: Line 1,881:
Abidjan, 4.4
Abidjan, 4.4
Casablanca, 3.98
Casablanca, 3.98
)</lang>
)</syntaxhighlight>


And here are the required computations:
And here are the required computations:


<lang J> (0 { data) i. <'Dar Es Salaam'
<syntaxhighlight lang="j"> (0 { data) i. <'Dar Es Salaam'
6
6
(i. >./)@(* 5&>)@:>@{: data
(i. >./)@(* 5&>)@:>@{: data
5
5
5 {:: 0 {data
5 {:: 0 {data
Khartoum-Omdurman</lang>
Khartoum-Omdurman
(1 { data) {::~ 'A' i.~ {.&> 0 { data
4.58</syntaxhighlight>


The "general search function" mentioned in the task does not seem a natural fit for this set of data, because of the multi-column nature of this data. Nevertheless, we could for example define:
The "general search function" mentioned in the task does not seem a natural fit for this set of data, because of the multi-column nature of this data. Nevertheless, we could for example define:


<lang j>gsf=: 1 :0
<syntaxhighlight lang="j">gsf=: 1 :0
:
:
I. u x { y
I. u x { y
)</lang>
)</syntaxhighlight>


This uses the single argument aspect of the definition of <code>I.</code> to convert a bit mask to the corresponding sequence of indices. And the column(s) we are searching on are exposed as a parameter for the interface, which allows us to ignore (for this problem) the irrelevant columns...
This uses the single argument aspect of the definition of <code>I.</code> to convert a bit mask to the corresponding sequence of indices. And the column(s) we are searching on are exposed as a parameter for the interface, which allows us to ignore (for this problem) the irrelevant columns...
Line 357: Line 1,905:
Thus, we could say:
Thus, we could say:


<lang J> 1 (= >./)@(* 5&>)@:> gsf data
<syntaxhighlight lang="j"> 1 (= >./)@(* 5&>)@:> gsf data
5</lang>
5</syntaxhighlight>


But this doesn't seem any clearer or more concise than our previous expression which finds the index of the first example of the most populous city with a population less than five million. Not only that, but if there were multiple cities which had the same population number which satisfied this constraint, this version would return all of those indices where the task explicitly required we return the first example.
But this doesn't seem any clearer or more concise than our previous expression which finds the index of the first example of the most populous city with a population less than five million. Not only that, but if there were multiple cities which had the same population number which satisfied this constraint, this version would return all of those indices where the task explicitly required we return the first example.


=== J: Another approach ===
=== J: Another approach ===
The following approach is arguably more natural in J than requiring a dictionary-type structure.

<lang j> city=: <;._1 ';Lagos;Cairo;Kinshasa-Brazzaville;Greater Johannesburg;Mogadishu;Khartoum-Omdurman;Dar Es Salaam;Alexandria;Abidjan;Casablanca'
<syntaxhighlight lang="j"> city=: <;._1 ';Lagos;Cairo;Kinshasa-Brazzaville;Greater Johannesburg;Mogadishu;Khartoum-Omdurman;Dar Es Salaam;Alexandria;Abidjan;Casablanca'
popln=: 21 15.2 11.3 7.55 5.85 4.98 4.7 4.58 4.4 3.98
popln=: 21 15.2 11.3 7.55 5.85 4.98 4.7 4.58 4.4 3.98
city i. <'Dar Es Salaam' NB. index of Dar Es Salaam
city i. <'Dar Es Salaam' NB. index of Dar Es Salaam
6
6
city {~ (popln < 5) {.@# \: popln NB. name of first city with population less than 5 million
(city i. boxopen) 'Dar Es Salaam' NB. anonymous search function with city name as argument
6
┌─────────────────┐
city {::~ (popln < 5) {.@# \: popln NB. name of first city with population less than 5 million
│Khartoum-Omdurman│
Khartoum-Omdurman
└─────────────────┘</lang>
popln&(city {::~ \:@[ {.@#~ <) 5 NB. anonymous search function with popln limit as argument
Khartoum-Omdurman
popln {~ 'A' i.~ {.&> city NB. population of first city whose name starts with "A"
4.58
(popln {~ ({.&> city)&i.) 'A' NB. anonymous search function with first letter as argument
4.58</syntaxhighlight>


=={{header|JavaScript}}==
=={{header|Java}}==


Java (up to and including) version 7 was not capable of using Predicates or the mentioned higher-order-Programming without external libraries. Java 8 introduced Predicated and Streams (not to be confused with the Java-IO-Streams!) that changed the way how collections of objects can be processed. This example illustrates the changes by solving the three subtasks in different ways:
===ES5===
<ol>
<li> "find the index of the fist city [...]" uses a predicate, but the actual search is done using classic iteration (this is also because the streams don't maintain anything "index-like" and so this would not be possible using stream-processing).
<li> "find city name by population [...]" uses a predicate to descibe the "search term" and returns the name of the city
<li> "find the population by letter [...]" uses a predicate as search term and accepts a "consumer" so the caller of the method specifies what to do with the found result.
</ol>
{{works with|Java|8}}


<syntaxhighlight lang="java">import java.util.Arrays;
{{update|JavaScript|
import java.util.Collections;
* The stuff about searching simple lists of strings or numbers, doesn't belong here. Maybe move it to [[Search a list]].
import java.util.List;
* A third test-case (search condition) has been added to the task description.
import java.util.function.Consumer;
}}
import java.util.function.Predicate;


/**
For arrays containing simple string and numeric datatypes, JavaScript provides '''Array.toIndex()'''.
* Represent a City and it's population.
* City-Objects do have a natural ordering, they are ordered by their poulation (descending)
*/
class City implements Comparable<City> {
private final String name;
private final double population;


City(String name, double population) {
Note that JS uses two different equality operators for simple types:
this.name = name;
:# Under Abstract equality, ''3.0 == '3''' -> ''true'' (http://www.ecma-international.org/ecma-262/5.1/#sec-9.12)
this.population = population;
:# Under Strict equality, ''3.0 === '3''' -> ''false'' http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.6
}


public String getName() {
and ''Array.toIndex'' matches only on Strict equality. Therefore:
return this.name;
}


public double getPopulation() {
<lang JavaScript>(function () {
return this.population;
var blnAbstractEquality = (3.0 == '3'), // true http://www.ecma-international.org/ecma-262/5.1/#sec-9.12
}
blnStrictEquality = (3.0 === '3'); // false; http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.6


@Override
var lstNumerics = [1, 1.0, '1', 2, 2.0, '2', 3, 3.0, '3'];
public int compareTo(City o) {
//compare for descending order. for ascending order, swap o and this
return Double.compare(o.population, this.population);
}
}


public class SearchListOfRecords {
return [
blnAbstractEquality,
blnStrictEquality,
lstNumerics.indexOf(3.0),
lstNumerics.indexOf('3')
]
})();</lang>


public static void main(String[] args) {
Returns:


//Array-of-City-Objects-Literal
<lang JavaScript>[
City[] datasetArray = {new City("Lagos", 21.),
true,
new City("Cairo", 15.2),
false,
new City("Kinshasa-Brazzaville", 11.3),
6,
new City("Greater Johannesburg", 7.55),
8
new City("Mogadishu", 5.85),
]</lang>
new City("Khartoum-Omdurman", 4.98),
new City("Dar Es Salaam", 4.7),
new City("Alexandria", 4.58),
new City("Abidjan", 4.4),
new City("Casablanca", 3.98)};


//Since this is about "collections smarter that arrays", the Array is converted to a List
Strict Equality does not, however, return true for two instances of objects which match identically in terms of their keys and values. This means that Array.indexOf() will alway return a -1 value (not found) in searches for objects other than simple strings and numbers. For strings, Strict Equality is case-sensitive.
List<City> dataset = Arrays.asList(datasetArray);


//the City-Objects know that they are supposed to be compared by population
To find more complex objects in a JS ES5 array, or search more flexibly, we can define '''find()''', and '''findIndex()''', which take predicate functions (defining the match required) as arguments:
Collections.sort(dataset);


The following code:


//Find the first City that matches the given predicate and print it's index in the dataset
<lang JavaScript>(function (fnNameMatch, fnPopulationMatch) {
//the Predicate here is given in the form a Java 8 Lambda that returns true if the given name
//Note that the Predicate is not limited to searching for names. It can operate on anything one can done with
// and compared about City-Objects
System.out.println(findIndexByPredicate(dataset, city -> city.getName().equals("Dar Es Salaam")));


//Find the first City whose population matches the given Predicate (here: population <= 5.) and print it's name
function find(fnPredicate, list) {
for (var i = 0, lng = list.length; i < lng; i++) {
//here the value is returned an printed by the caller
System.out.println(findFirstCityByPredicate(dataset, city -> city.getPopulation() <= 5.));
if (fnPredicate(list[i])) {
return list[i];
}
}
return undefined;
};


//Find the first City that matches the given predicate (here: name starts with "A") and
function findIndex(fnPredicate, list) {
//apply the given consumer (here: print the city's population)
for (var i = 0, lng = list.length; i < lng; i++) {
//here the caller specifies what to do with the object. This is the most generic solution and could also be used to solve Task 2
if (fnPredicate(list[i])) {
applyConsumerByPredicate(dataset, city -> city.getName().startsWith("A"), city -> System.out.println(city.getPopulation()));
return i;

}

/**
* Finds a City by Predicate.
* The predicate can be anything that can be done or compared about a City-Object.
* <p>
* Since the task was to "find the index" it is not possible to use Java 8's stream facilities to solve this.
* The Predicate is used very explicitly here - this is unusual.
*
* @param dataset the data to operate on, assumed to be sorted
* @param p the Predicate that wraps the search term.
* @return the index of the City in the dataset
*/
public static int findIndexByPredicate(List<City> dataset, Predicate<City> p) {
for (int i = 0; i < dataset.size(); i++) {
if (p.test(dataset.get(i)))
return i;
}
}
}
return -1;
}
return undefined;
};


/**
var lstCities = [{
* Finds and returns the name of the first City where the population matches the Population-Predicate.
"name": "Lagos",
* This solutions makes use of Java 8's stream facilities.
"population": 21
}, {
*
* @param dataset the data to operate on, assumed to be sorted
"name": "Cairo",
* @param predicate a predicate that specifies the city searched. Can be "any predicate that can be applied to a City"
"population": 15.2
* @return the name of the first City in the dataset whose population matches the predicate
}, {
*/
"name": "Kinshasa-Brazzaville",
private static String findFirstCityByPredicate(List<City> dataset, Predicate<City> predicate) {
"population": 11.3
//turn the List into a Java 8 stream, so it can used in stream-operations
}, {
//filter() by the specified predicate (to the right of this operation, only elements matching the predicate are left in the stream)
"name": "Greater Johannesburg",
//find the first element (which is "the first city..." from the task)
"population": 7.55
//get() the actualy object (this is necessary because it is wrapped in a Java 8 Optional<T>
}, {
"name": "Mogadishu",
//getName() the name and return it.
return dataset.stream().filter(predicate).findFirst().get().getName();
"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
}];


return [
/**
* In specified dataset, find the first City whose name matches the specified predicate, and apply the specified consumer
lstCities.indexOf({
* <p>
"name": "Alexandria",
* Since this can be solved pretty much like the "find a city by population", this has been varied. The caller specifies what to do with the result.
"population": 4.58
* So this method does not return anything, but requiers a "consumer" that processes the result.
}),
*
* @param dataset the data to operate on, assumed to be sorted
* @param predicate a predicate that specifies the city searched. Can be "any predicate that can be applied to a City"
* @param doWithResult a Consumer that specified what to do with the results
*/
private static void applyConsumerByPredicate(List<City> dataset, Predicate<City> predicate, Consumer<City> doWithResult) {
//turn the List in to a Java 8 stream in stream-operations
//filter() by the specified predicate (to the right of this operation, only elements matching the predicate are left in the stream)
//find the first element (which is "the first city..." from the task)
// if there is an element found, feed it to the Consumer
dataset.stream().filter(predicate).findFirst().ifPresent(doWithResult);
}
}
</syntaxhighlight>


{{Out}}
find(fnNameMatch, lstCities),
<pre>6
findIndex(fnNameMatch, lstCities),
Khartoum-Omdurman
4.58</pre>


=={{header|JavaScript}}==
find(fnPopulationMatch, lstCities),
findIndex(fnPopulationMatch, lstCities)
]


===ES5===
})(
function (e) {
return e.name && e.name.toLowerCase() === 'dar es salaam';


<syntaxhighlight lang="javascript">(function () {
},
function (e) {
'use strict';
return e.population && e.population < 5.0;
// find :: (a -> Bool) -> [a] -> Maybe a
function find(f, xs) {
for (var i = 0, lng = xs.length; i < lng; i++) {
if (f(xs[i])) return xs[i];
}
return undefined;
}
}
);
// findIndex :: (a -> Bool) -> [a] -> Maybe Int
function findIndex(f, xs) {
for (var i = 0, lng = xs.length; i < lng; i++) {
if (f(xs[i])) return i;
}
return undefined;
}
var lst = [
{ "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 }
];
return {
darEsSalaamIndex: findIndex(function (x) {
return x.name === 'Dar Es Salaam';
}, lst),
firstBelow5M: find(function (x) {
return x.population < 5;
}, lst)
.name,
firstApop: find(function (x) {
return x.name.charAt(0) === 'A';
}, lst)
.population
};
})();</syntaxhighlight>


})();</lang>


{{Out}}
returns:
<pre>{"darEsSalaamIndex":6, "firstBelow5M":"Khartoum-Omdurman", "firstApop":4.58}</pre>
<lang JavaScript>[
-1, // the Alexandria object can not be found with Array.indexOf()
{
"name": "Dar Es Salaam",
"population": 4.7
},
6,
{
"name": "Khartoum-Omdurman",
"population": 4.98
},
5
]</lang>


===ES6===
===ES6===


<syntaxhighlight lang="javascript">(() => {
{{improve|JavaScript|please show actual code that performs the searches specified in the task description}}
'use strict';
let lst = [
{ "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 }
];
return {
darEsSalaamIndex: lst.findIndex(x => x.name === 'Dar Es Salaam'),
firstBelow5M: lst.find(x => x.population < 5)
.name,
firstApop: lst.find(x => x.name[0] === 'A')
.population
};
})();</syntaxhighlight>


In ES6, Array.find() and Array.findIndex() are provided as built-in methods, but beware that these are not supported in IE.


=={{header|Perl}}==
{{Out}}
<pre>{"darEsSalaamIndex":6, "firstBelow5M":"Khartoum-Omdurman", "firstApop":4.58}</pre>


=={{header|jq}}==
{{update|Perl|

* The stuff about searching simple lists of strings, doesn't belong here. Maybe move it to [[Search a list]].
"jq" is so-name because it is a JSON Query Language, and thus all the abstractions are already available for the given searches, except that early versions of jq do not have `first/1` as a builtin. If your jq does not define `first/1`, then for present purposes, an appropriate definition would be:
* You shouldn't parse the input from JSON - instead, show to readers what the data structure looks like natively.

* The code uses a hard-coded loop for each search. Consider a more generic and re-usable approach as asked for by the task description, or explain to readers why that wasn't possible or sensible in this language.
<syntaxhighlight lang="jq">def first(s): [s][0];</syntaxhighlight>
}}

This will emit `null` if the stream, s, is empty.

In each case where `first/1` is used below, a less efficient alternative is also shown.

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

map(.name) | index("Dar Es Salaam")

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

first(.[] | select(.population < 5)) | .name

# Alternatively:

map(select(.population < 5)) | .[0] | .name

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

first(.[] | select(.name[0:1] == "A")) | .population

# Alternatively:

map(select(.name[0:1] == "A")) | .[0] | .population

=={{header|Julia}}==
{{works with|Julia|0.6}}

<syntaxhighlight lang="julia">using DataFrames

dataset = DataFrame(name=["Lagos", "Cairo", "Kinshasa-Brazzaville", "Greater Johannesburg", "Mogadishu",
"Khartoum-Omdurman", "Dar Es Salaam", "Alexandria", "Abidjan", "Casablanca"],
population=[21.0, 15.2, 11.3, 7.55, 5.85, 4.98, 4.7, 4.58, 4.4, 3.98])

print("Find the (one-based) index of the first city in the list whose name is \"Dar Es Salaam\": ")
println(findfirst(dataset[:name], "Dar Es Salaam"))
print("Find the name of the first city in this list whose population is less than 5 million: ")
println(dataset[first(find(dataset[:population] .< 5)), :name])
print("Find the population of the first city in this list whose name starts with the letter \"A\": ")
println(dataset[first(find(startswith.(dataset[:name], 'A'))), :population])</syntaxhighlight>

{{out}}
<pre>Find the (one-based) index of the first city in the list whose name is "Dar Es Salaam": 7
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</pre>

=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.1.2

class City(val name: String, val pop: Double)

val cities = listOf(
City("Lagos", 21.0),
City("Cairo", 15.2),
City("Kinshasa-Brazzaville", 11.3),
City("Greater Johannesburg", 7.55),
City("Mogadishu", 5.85),
City("Khartoum-Omdurman", 4.98),
City("Dar Es Salaam", 4.7),
City("Alexandria", 4.58),
City("Abidjan", 4.4),
City("Casablanca", 3.98)
)

fun main(args: Array<String>) {
val index = cities.indexOfFirst { it.name == "Dar Es Salaam" }
println("Index of first city whose name is 'Dar Es Salaam' = $index")
val name = cities.first { it.pop < 5.0 }.name
println("Name of first city whose population is less than 5 million = $name")
val pop = cities.first { it.name[0] == 'A' }.pop
println("Population of first city whose name starts with 'A' = $pop")
}</syntaxhighlight>

{{out}}
<pre>
Index of first city whose name is 'Dar Es Salaam' = 6
Name of first city whose population is less than 5 million = Khartoum-Omdurman
Population of first city whose name starts with 'A' = 4.58
</pre>

=={{header|Lingo}}==
<syntaxhighlight lang="lingo">on findFirstRecord (data, condition)
cnt = data.count
repeat with i = 1 to cnt
record = data[i]
if value(condition) then return [#index:i-1, #record:record]
end repeat
end</syntaxhighlight>

<syntaxhighlight lang="lingo">data = [\
[ "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 ]\
]
q = QUOTE

-- Find the (zero-based) index of the first city in the list whose name is "Dar Es Salaam"
res = findFirstRecord(data, "record.name="&q&"Dar Es Salaam"&q)
if listP(res) then put res.index
-- 6

-- Find the name of the first city in this list whose population is less than 5 million
res = findFirstRecord(data, "record.population<5")
if listP(res) then put res.record.name
-- "Khartoum-Omdurman"

-- Find the population of the first city in this list whose name starts with the letter "A"
res = findFirstRecord(data, "record.name.char[1]="&q&"A"&q)
if listP(res) then put res.record.population
-- 4.5800</syntaxhighlight>


=={{header|Lua}}==
<lang perl>if(grep $_ eq $needle, @haystack) {
Lua tables are well suited as the element type for this task. The master data structure is a table of tables.
print 'Found';
<syntaxhighlight lang="lua">-- Dataset declaration
local cityPops = {
{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}
}
}


-- Function to search a dataset using a custom match function
print grep($_ eq 'needle', ('apple', 'orange')) ? 'Found' : 'Not found';
function recordSearch (dataset, matchFunction)
local returnValue
for index, element in pairs(dataset) do
returnValue = matchFunction(index, element)
if returnValue then return returnValue end
end
return nil
end


-- Main procedure
specifically solving the problem above
local testCases = {
#!/usr/bin/perl
function (i, e) if e.name == "Dar Es Salaam" then return i - 1 end end,
use strict ;
function (i, e) if e.population < 5 then return e.name end end,
use warnings ;
function (i, e) if e.name:sub(1, 1) == "A" then return e.population end end
use JSON ;
}
for _, func in pairs(testCases) do print(recordSearch(cityPops, func)) end</syntaxhighlight>
{{out}}
<pre>6
Khartoum-Omdurman
4.58</pre>


=={{header|Ksh}}==
my $african_cities =
<syntaxhighlight lang="ksh">
' [
#!/bin/ksh
{"name":"Lagos","population":21},
{"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}
]' ;


# Search a list of records
my $cityhash = from_json ( $african_cities ) ;

my $current = 0 ;
# # Variables:
while ( $cityhash->[$current]->{"name"} ne "Dar Es Salaam" ) {
#
$current++ ;
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 }'

typeset -a African_Metro
integer i=0

typeset -T Metro_Africa_t=(
typeset -h 'Metro name' met_name=''
typeset -E3 -h 'Metro population' met_pop

function init_metro {
typeset name ; name="$1"
typeset pop ; typeset -E3 pop=$2

_.met_name=${name}
_.met_pop=${pop}
}

function prt_name {
print "${_.met_name}"
}

function prt_pop {
print "${_.met_pop}"
}
)

# # Functions:
#

# # Function _findcityindex(arr, name) - return array index of citry named "name"
#
function _findcityindex {
typeset _arr ; nameref _arr="$1"
typeset _name ; _name="$2"
typeset _i ; integer _i

for ((_i=0; _i<${#_arr[*]}; _i++)); do
[[ ${_name} == $(_arr[_i].prt_name) ]] && echo ${_i} && return 0
done
echo "-1"
return 1
}
}

print "Dar Es Salaam has the index $current!\n" ;
# # Function _findcitynamepop(arr, pop, xx) - find 1st city name pop $3 of $2
$current = 0 ;
#
while ( $cityhash->[$current]->{"population"} >= 5.0 ) {
function _findcitynamepop {
$current++ ;
typeset _arr ; nameref _arr="$1"
typeset _pop ; typeset -E3 _pop=$2
typeset _comp ; _comp="$3"
typeset _i ; integer _i

for ((_i=0; _i<${#_arr[*]}; _i++)); do
case ${_comp} in
gt)
[[ $(_arr[_i].prt_pop) -gt ${_pop} ]] && _arr[_i].prt_name && return 0 ;;
lt)
[[ $(_arr[_i].prt_pop) -lt ${_pop} ]] && _arr[_i].prt_name && return 0 ;;
esac
done
echo "DNE"
return 1
}
}

print "The first city with a population of less than 5 million is "
# # Function _findcitypopname(arr, pat) - find pop of first city starting w/ pat
. $cityhash->[$current]->{"name"} . " !\n" ;</lang>
#
function _findcitypopname {
typeset _arr ; nameref _arr="$1"
typeset _pat ; _pat="$2"
typeset _i ; integer _i

for ((_i=0; _i<${#_arr[*]}; _i++)); do
[[ $(_arr[_i].prt_name) == ${_pat}* ]] && _arr[_i].prt_pop && return 0
done
echo "-1"
return 1
}

######
# main #
######

# # An indexed array of Type variable (objects)
#
echo "${json}" | while read; do
metro="${REPLY#*\"name\"\:\ }" ; metro="${metro%%\,*}" ; metro="${metro//\"/}"
population="${REPLY#*\"population\"\:\ }" ; population=${population%+(\ )\}*(\,)}

Metro_Africa_t African_Metro[i]
African_Metro[i++].init_metro "${metro}" ${population}
done

_findcityindex African_Metro "Dar Es Salaam"
_findcitynamepop African_Metro 5.0 lt
_findcitypopname African_Metro "A"</syntaxhighlight>
{{out}}<pre>
6
Khartoum-Omdurman
4.58</pre>

=={{header|Maple}}==
<syntaxhighlight lang="maple">rec := [table(["name"="Lagos","population"=21.0]),
table(["name"="Cairo","population"=15.2]),
table(["name"="Kinshasa-Brazzaville","population"=11.3]),
table(["name"="Greater Johannesburg","population"=7.55]),
table(["name"="Mogadishu","population"=5.85]),
table(["name"="Khartoum-Omdurman","population"=4.98]),
table(["name"="Dar Es Salaam","population"=4.7 ]),
table(["name"="Alexandria","population"=4.58]),
table(["name"="Abidjan","population"=4.4]),
table(["name"="Casablanca","population"=3.98])]:

searchRec := proc(rec, pred, operation)
local i:
for i to numelems(rec) do
if pred(rec[i]) then
return operation(rec[i],i):
fi:
od:
end proc:
searchRec(rec, x->x["name"] = "Dar Es Salaam", (x,i)->print(i-1)): # minus 1 since Maple is 1-indexed
searchRec(rec, x->x["population"]<5, (x,i)->print(x["name"])):
searchRec(rec, x->x["name"][1] = "A", (x,i)->print(x["population"])):</syntaxhighlight>
{{out}}
{{out}}
<pre>Dar Es Salaam has the index 6!
<pre> 6
The first city with a population of less than 5 million is Khartoum-Omdurman !</pre>
"Khartoum-Omdurman"
4.58
</pre>


=={{header|Perl 6}}==
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">data = Dataset[{
<|"name" -> "Lagos", "population" -> 21.|>,
<|"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|>
}]
data[Position["Dar Es Salaam"], "name"][1, 1] - 1
data[Select[#population < 5 &]][1, "name"]
data[Select[StringMatchQ[#name, "A*"] &]][1, "population"]</syntaxhighlight>


=={{header|Nim}}==
{{update|Perl 6|
To solve this task, we define a template “findIt” similar to the templates provided by the standard library module “sequtils”. As First argument it accepts any collection providing a “pairs” iterator (yielding an index and a value), for instance a sequence (list) or a table (hash). The second argument of the template is a predicate, i.e. an expression containing the “it” variable.
* You shouldn't parse the input from JSON - instead, show to readers what the data structure looks like natively.
* A third test-case (search condition) has been added to the task description.
* The second test-case has been clarified to no longer require sort.
}}


This way, the template is able to work in a lot of contexts.
{{Works with|rakudo|2015-11-29}}
There are several search operations that may be used. It mostly depends on whether you want to find actual values or pointers, and/or all possible values or a single value matching your criteria. The most appropriate for the given test data/operations are shown here.


<syntaxhighlight lang="nim">template findIt(data, pred: untyped): int =
<lang perl6>use JSON::Tiny;
## Return the index of the first element in "data" satisfying
## the predicate "pred" or -1 if no such element is found.
var result = -1
for i, it {.inject.} in data.pairs:
if pred:
result = i
break
result


my $cities = from-json('
[{"name":"Lagos", "population":21}, {"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}]
');


when isMainModule:
# Find the indicies of the cities named 'Dar Es Salaam'.
say grep { $_<name> eq 'Dar Es Salaam'}, :k, @$cities; # (6)


import strutils
# Find the name of the first city with a population less
# than 5 when sorted by population, largest to smallest.
say ($cities.sort( -*.<population> ).first: *.<population> < 5)<name>; # Khartoum-Omdurman


type City = tuple[name: string; population: float]


const Cities: seq[City] = @[("Lagos", 21.0),
# Find all of the city names that contain an 'm'
("Cairo", 15.2),
say join ', ', sort grep( {$_<name>.lc ~~ /'m'/}, @$cities )»<name>; # Dar Es Salaam, Khartoum-Omdurman, Mogadishu</lang>
("Kinshasa-Brazzaville", 11.3),
("Greater Johannesburg", 7.55),
("Mogadishu", 5.85),
("Khartoum-Omdurman", 4.98),
("Dar Es Salaam", 4.7),
("Alexandria", 4.58),
("Abidjan", 4.4),
("Casablanca", 3.98)]


echo "Index of the first city whose name is “Dar Es Salaam”: ",
=={{header|Phix}}==
Cities.findIt(it.name == "Dar Es Salaam")


let idx1 = Cities.findIt(it.population < 5)
{{update|Phix|
echo "Name of the first city whose population is less than 5 million: ",
* A third test-case (search condition) has been added to the task description.
if idx1 == -1: "<none>" else: Cities[idx1].name
}}


let idx2 = Cities.findIt(it.name.startsWith("A"))
<lang Phix>constant CITY_NAME = 1, POPULATION = 2
echo "Population of the first city whose name starts with the letter “A”: ",
constant municipalities = {{"Lagos",21},
if idx2 == -1: "<none>" else: $Cities[idx2].population</syntaxhighlight>
{"Cairo",15.2},
{"Kinshasa-Brazzaville",11.3},
{"Greater Johannesburg",7.55},
{"Mogadishu",5.85},
{"Khartoum-Omdurman",4.98},
{"Dar Es Salaam",4.7},
{"Alexandria",4.58},
{"Abidjan",4.4},
{"Casablanca",3.98}}


{{out}}
function searchfor(sequence s, integer rid, object user_data, integer return_index=0)
<pre>Index of the first city whose name is “Dar Es Salaam”: 6
for i=1 to length(s) do
Name of the first city whose population is less than 5 million: Khartoum-Omdurman
if call_func(rid,{s[i],user_data}) then
Population of the first city whose name starts with the letter “A”: 4.58</pre>
return iff(return_index?i:s[i])
end if
end for
return 0 -- not found
end function


=={{header|OCaml}}==
function city_named(sequence si, string city_name)
{{works with|OCaml|4.03+}}
return si[CITY_NAME]=city_name
<syntaxhighlight lang="ocaml">
end function
#load "str.cma"


?searchfor(municipalities,routine_id("city_named"),"Dar Es Salaam",1)


(* We are going to use literally a list of records as said in the title of the
function smaller_than(sequence si, atom population)
* task. *)
return si[POPULATION]<population
(* First: Definition of the record type. *)
end function
type city = {
name : string;
population : float
}


(* Second: The actual list of records containing the data. *)
?searchfor(municipalities,routine_id("smaller_than"),5)[CITY_NAME]</lang>
let cities = [
{ 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 }
]


(* I can't find in the standard library any function in module List that returns
* an index. Well, never mind, I make my own... *)
let find_index pred =
let rec doloop i = function
| [] -> raise Not_found
| x :: xs -> if pred x then i else doloop (i + 1) xs
in
doloop 0


(* List.find returns the first element that satisfies the predicate.
* List.filter or List.find_all would return *all* the elements that satisfy the
* predicate. *)
let get_first pred = List.find pred


(* Simulate the 'startswith' function found in other languages. *)
let startswith sub s =
Str.string_match (Str.regexp sub) s 0


let () =
(* We use a typical dot notation to access the record fields. *)
find_index (fun c -> c.name = "Dar Es Salaam") cities
|> print_int
|> print_newline;

(get_first (fun c -> c.population < 5.0) cities).name
|> print_endline;

(get_first (fun c -> startswith "A" c.name) cities).population
|> print_float
|> print_newline;
</syntaxhighlight>
{{out}}
6
Khartoum-Omdurman
4.58
=={{header|Pascal}}==
==={{header|Free Pascal}}===
<syntaxhighlight lang="pascal">
program Search_list_records;
{$mode ObjFPC}{$H+}

type
TCity = record
name: string;
population: real;
end;

const
Cities: array of TCity = (
(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)
);

function FindCityIndex(const CityName: string): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to High(Cities) do
if Cities[i].name = CityName then
Exit(i);
end;

function FindCityName(const pop: real): string;
var
City: TCity;
begin
Result := 'not found';
for City in Cities do
if City.population < pop then
Exit(City.name);
end;

function FindCityPopulation(const Start: Char): Real;
var
City: TCity;
begin
Result := -1;
for City in Cities do
if City.name[1] = Start then
Exit(City.population);
end;

begin
writeln('index: ', FindCityIndex('Dar Es Salaam'));
writeln('name: ', FindCityName(5.0));
writeln('population: ', FindCityPopulation('A'):4:2);
end.

</syntaxhighlight>
{{out}}
<pre>
index: 6
name: Khartoum-Omdurman
population: 4.58
</pre>

=={{header|Perl}}==

The <tt>first</tt> function from the core module <tt>List::Util</tt> provides short-circuiting search using a block as predicate. However, it can only return the value of the found element, not its index &ndash; so for the first test-case we need to operate on the list of indices.

<syntaxhighlight lang="perl">use feature 'say';
use List::Util qw(first);

my @cities = (
{ 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 },
);

my $index1 = first { $cities[$_]{name} eq 'Dar Es Salaam' } 0..$#cities;
say $index1;

my $record2 = first { $_->{population} < 5 } @cities;
say $record2->{name};

my $record3 = first { $_->{name} =~ /^A/ } @cities;
say $record3->{population};</syntaxhighlight>

{{out}}
<pre>
6
Khartoum-Omdurman
4.58
</pre>

The CPAN module <tt>List::MoreUtils</tt> provides the <tt>first_index</tt> function which could be used to write that first case more elegantly:

<syntaxhighlight lang="perl">use List::MoreUtils qw(first_index);

$index1 = first_index { $_->{name} eq 'Dar Es Salaam' } @cities;</syntaxhighlight>

=={{header|Phix}}==
{{libheader|Phix/basics}}
<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">constant</span> <span style="color: #000000;">CITY_NAME</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">POPULATION</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">2</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">municipalities</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #008000;">"Lagos"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">21</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Cairo"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">15.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Kinshasa-Brazzaville"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">11.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Greater Johannesburg"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7.55</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Mogadishu"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.85</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Khartoum-Omdurman"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.98</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Dar Es Salaam"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.7</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Alexandria"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.58</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Abidjan"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"Casablanca"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.98</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">searchfor</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">rid</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">object</span> <span style="color: #000000;">user_data</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">bool</span> <span style="color: #000000;">return_index</span><span style="color: #0000FF;">=</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">rid</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">user_data</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #008080;">iff</span><span style="color: #0000FF;">(</span><span style="color: #000000;">return_index</span><span style="color: #0000FF;">?</span><span style="color: #000000;">i</span><span style="color: #0000FF;">:</span><span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- not found</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">city_named</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">city_name</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">[</span><span style="color: #000000;">CITY_NAME</span><span style="color: #0000FF;">]==</span><span style="color: #000000;">city_name</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">searchfor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">municipalities</span><span style="color: #0000FF;">,</span><span style="color: #000000;">city_named</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Dar Es Salaam"</span><span style="color: #0000FF;">,</span><span style="color: #004600;">true</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">smaller_than</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">population</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">[</span><span style="color: #000000;">POPULATION</span><span style="color: #0000FF;">]<</span><span style="color: #000000;">population</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">searchfor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">municipalities</span><span style="color: #0000FF;">,</span><span style="color: #000000;">smaller_than</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">CITY_NAME</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">starts_with</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">si</span><span style="color: #0000FF;">[</span><span style="color: #000000;">CITY_NAME</span><span style="color: #0000FF;">][</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]=</span><span style="color: #000000;">ch</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">searchfor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">municipalities</span><span style="color: #0000FF;">,</span><span style="color: #000000;">starts_with</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'A'</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">POPULATION</span><span style="color: #0000FF;">]</span>
<!--</syntaxhighlight>-->
The columnize function reorganises hetrogenous data into corresponding homogenous arrays, which can make this sort of thing much simpler,
The columnize function reorganises hetrogenous data into corresponding homogenous arrays, which can make this sort of thing much simpler,
at least for exact matches.
at least for exact matches.
<lang Phix>constant {cities,populations} = columnize(municipalities)


<!--<syntaxhighlight lang="phix">-->
?find(cities,"Dar Es Salaam")</lang>
<span style="color: #008080;">constant</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">cities</span><span style="color: #0000FF;">,</span><span style="color: #000000;">populations</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">columnize</span><span style="color: #0000FF;">(</span><span style="color: #000000;">municipalities</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">populations</span><span style="color: #0000FF;">[</span><span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Dar Es Salaam"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">cities</span><span style="color: #0000FF;">)]</span>
<!--</syntaxhighlight>-->

{{out}}
{{out}}
<pre>
<pre>
7
7
"Khartoum-Omdurman"
"Khartoum-Omdurman"
4.58
7
4.7
</pre>
</pre>
Note that Phix subscripts are 1-based, hence the output of 7 not 6.
Note that Phix subscripts are 1-based, hence the output of 7 not 6.

=={{header|Phixmonti}}==
<syntaxhighlight lang="Phixmonti">include ..\Utilitys.pmt

(
( "Lagos" 21.0 )
( "Cairo" 15.2 )
( "Kinshasa-Brazzaville" 11.3 )
( "Greater Johannesburg" 7.55 )
( "Mogadishu" 5.85 )
( "Khartoum-Omdurman" 4.98 )
( "Dar Es Salaam" 4.7 )
( "Alexandria" 4.58 )
( "Abidjan" 4.4 )
( "Casablanca" 3.98 )
)

len for >ps
( tps 1 ) sget "Dar Es Salaam" == if ps> 1 - ? exitfor else cps endif
endfor

len for
get 2 get 5 < if 1 get ? drop exitfor else drop endif
endfor

len for >ps
( tps 1 1 ) sget 'A' == if ( ps> 2 ) sget ? exitfor else cps endif
endfor</syntaxhighlight>
{{out}}
<pre>6
Khartoum-Omdurman
4.58

=== Press any key to exit ===</pre>


=={{header|PHP}}==
=={{header|PHP}}==
<syntaxhighlight lang="php">
<?php


$data_array = [
{{incorrect|PHP|
['name' => 'Lagos', 'population' => 21.0],
* The stuff about searching simple lists of strings or numbers, doesn't belong here. Maybe move it to [[Search a list]].
['name' => 'Cairo', 'population' => 15.2],
* Solve the problem specified in the task description instead.
['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],
];
$found=0;
$search_name = 'Dar Es Salaam';
echo "Find the (zero-based) index of the first city in the list whose name is \"$search_name\" - 6";


$index = array_search($search_name, array_column($data_array, 'name'));
<lang PHP>echo in_array('needle', ['hay', 'stack']) ? 'Found' : 'Not found';</lang>
$population = $data_array[$index]['population'];
echo "\nAnswer 1: Index: [$index] Population for $search_name is $population Million\n";
$search_val = 5;
echo "\nFind the name of the first city in this list whose population is less than $search_val million - Khartoum-Omdurman";
foreach ($data_array as $index => $row) {
if ($row['population'] < $search_val) {
$name = $row['name'];
echo "\nAnswer 2: Index [$index] Population for $row[name] is $row[population] Million\n";
break;
}
}
$search_term = 'A';
echo "\n\nFind the population of the first city in this list whose name starts with the letter \"$search_term\" - 4.58";
foreach ($data_array as $index => $row) {
if (strpos($row['name'], $search_term) === 0) {
echo "\nAnswer 3: Index: [$index] Population for $row[name] is $row[population] Million\n";
break;
}
}
echo "\nDone...";


Output:
=={{header|Racket}}==
Find the (zero-based) index of the first city in the list whose name is "Dar Es Salaam" - 6
Answer 1: Index: [6] Population for Dar Es Salaam is 4.7 Million


Find the name of the first city in this list whose population is less than 5 million - Khartoum-Omdurman
{{update|Racket|
Answer 2: Index [5] Population for Khartoum-Omdurman is 4.98 Million
* A third test-case (search condition) has been added to the task description.

}}
Find the population of the first city in this list whose name starts with the letter "A" - 4.58
Answer 3: Index: [7] Population for Alexandria is 4.58 Million

Done...
</syntaxhighlight>

=={{header|PicoLisp}}==
<syntaxhighlight lang="picolisp">(scl 2)

(de *Data
("Lagos" 21.0)
("Cairo" 15.2)
("Kinshasa-Brazzaville" 11.3)
("Greater Johannesburg" 7.55)
("Mogadishu" 5.85)
("Khartoum-Omdurman" 4.98)
("Dar Es Salaam" 4.7)
("Alexandria" 4.58)
("Abidjan" 4.4)
("Casablanca" 3.98) )

(test 6
(dec (index (assoc "Dar Es Salaam" *Data) *Data)) )

(test "Khartoum-Omdurman"
(car (find '((L) (> 5.0 (cadr L))) *Data)) )

(test 4.58
(cadr (find '((L) (pre? "A" (car L))) *Data)) )</syntaxhighlight>

=={{header|PowerShell}}==
The <code>ConvertFrom-Json</code> cmdlet converts a JSON formatted string to a custom PSCustomObject object that has a property for each field in the JSON string:
<syntaxhighlight lang="powershell">
$jsonData = @'
[
{ "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 }
]
'@

$cities = $jsonData | ConvertFrom-JSON
</syntaxhighlight>
The <code>$cities</code> variable contains an array of objects with '''Name''' and '''Population''' properties:
<syntaxhighlight lang="powershell">
$cities
</syntaxhighlight>
{{Out}}
<pre>
Name Population
---- ----------
Lagos 21.0
Cairo 15.2
Kinshasa-Brazzaville 11.3
Greater Johannesburg 7.55
Mogadishu 5.85
Khartoum-Omdurman 4.98
Dar Es Salaam 4.7
Alexandria 4.58
Abidjan 4.4
Casablanca 3.98
</pre>
Find the index of the first city in the list whose name is "Dar Es Salaam":
<syntaxhighlight lang="powershell">
$cities.Name.IndexOf("Dar Es Salaam")
</syntaxhighlight>
{{Out}}
<pre>
6
</pre>
Find the name of the first city in this list whose population is less than 5 million:
<syntaxhighlight lang="powershell">
($cities | Where-Object -Property Population -LT 5)[0].Name
</syntaxhighlight>
{{Out}}
<pre>
Khartoum-Omdurman
</pre>
Find the population of the first city in this list whose name starts with the letter "A":
<syntaxhighlight lang="powershell">
($cities | Where-Object -Property Name -Match "^A")[0].Population
</syntaxhighlight>
{{Out}}
<pre>
4.58
</pre>

=={{header|Python}}==

<syntaxhighlight lang="python">cities = [
{ "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 }
]

def first(query):
return next(query, None)

print(
first(index for index, city in enumerate(cities)
if city['name'] == "Dar Es Salaam"),
first(city['name'] for city in cities if city['population'] < 5),
first(city['population'] for city in cities if city['name'][0] == 'A'),
sep='\n')</syntaxhighlight>

{{out}}
<pre>
6
Khartoum-Omdurman
4.58
</pre>

=={{header|Racket}}==


The more idiomatic functions for the task is <code>findf</code> but it doesn't provide the position of the element in the list, so we write a variant. If the item is not found we return <code>#f</code> as most of the Racket primitives do in these cases.
The more idiomatic functions for the task is <code>findf</code> but it doesn't provide the position of the element in the list, so we write a variant. If the item is not found we return <code>#f</code> as most of the Racket primitives do in these cases.
<lang Racket>#lang racket
<syntaxhighlight lang="racket">
#lang racket


(define (findf/pos proc lst)
(define (findf/pos proc lst)
Line 669: Line 3,001:
[(null? lst) #f]
[(null? lst) #f]
[(proc (car lst)) pos]
[(proc (car lst)) pos]
[else (loop (cdr lst) (add1 pos))])))</lang>
[else (loop (cdr lst) (add1 pos))])))
</syntaxhighlight>
Now we define the list that has the data for the task.
Now we define the list that has the data for the task.
<syntaxhighlight lang="racket">
<lang Racket>(define data '(("Lagos" 21)
(define data '(#hash((name . "Lagos") (population . 21))
("Cairo" 15.2)
("Kinshasa-Brazzaville" 11.3)
#hash((name . "Cairo") (population . 15.2))
("Greater Johannesburg" 7.55)
#hash((name . "Kinshasa-Brazzaville") (population . 11.3))
("Mogadishu" 5.85)
#hash((name . "Greater Johannesburg") (population . 7.55))
("Khartoum-Omdurman" 4.98)
#hash((name . "Mogadishu") (population . 5.85))
("Dar Es Salaam" 4.7)
#hash((name . "Khartoum-Omdurman") (population . 4.98))
("Alexandria" 4.58)
#hash((name . "Dar Es Salaam") (population . 4.7))
("Abidjan" 4.4)
#hash((name . "Alexandria") (population . 4.58))
("Casablanca" 3.98)))</lang>
#hash((name . "Abidjan") (population . 4.4))
#hash((name . "Casablanca") (population . 3.98))))
We write tiny wrappers to solve the specific task.
</syntaxhighlight>
<lang Racket>(define (city-pos name)
We write tiny wrappers to retrieve values from the hash.
(findf/pos (lambda (x) (string=? (car x) name)) data))
<syntaxhighlight lang="racket">
(define get-name
(lambda (x) (hash-ref x 'name)))


(define get-population
(city-pos "Dar Es Salaam")
(lambda (x) (hash-ref x 'population)))
(city-pos "Buenos Aires")
</syntaxhighlight>
For completeness, ensure the data is sorted by population largest to smallest.
<syntaxhighlight lang="racket">
(define sorted-data (sort data > #:key get-population))
</syntaxhighlight>
Use an unnamed function with our findf/pos function to get the position of "Dar Es Salaam".
<syntaxhighlight lang="racket">
(findf/pos (lambda (x) (equal? "Dar Es Salaam" (get-name x))) sorted-data)
;; -> 6
</syntaxhighlight>
Use unnamed functions with findf for the other two test cases.
<syntaxhighlight lang="racket">
(get-name (findf (lambda (x) (< (get-population x) 5)) sorted-data))
;; -> "Khartoum-Omdurman"
(get-population (findf (lambda (x) (regexp-match? #rx"^A" (get-name x))) sorted-data))
;; -> 4.58
</syntaxhighlight>
{{out}}
<pre>
6
"Khartoum-Omdurman"
4.58
</pre>


=={{header|Raku}}==
(define (city-smaller pop)
(formerly Perl 6)
(let ([city (findf (lambda (x) (< (cadr x) pop)) data)])

(and city (car city))))
The built-in method <tt>.first</tt> fulfills the requirements of this task.<br>
It takes any [https://docs.raku.org/language/operators#infix_~~ smart-matcher] as a predicate. The <tt>:k</tt> adverb makes it return the key (i.e. numerical index) instead of the value of the element.

{{Works with|Rakudo|2016.08}}
<syntaxhighlight lang="raku" line>my @cities =
{ 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 },
;

say @cities.first(*<name> eq 'Dar Es Salaam', :k);
say @cities.first(*<population> < 5).<name>;
say @cities.first(*<name>.match: /^A/).<population>;</syntaxhighlight>


(city-smaller 5)
(city-smaller -1)</lang>
{{out}}
{{out}}
<pre>6
<pre>
6
#f
"Khartoum-Omdurman"
Khartoum-Omdurman
4.58
#f</pre>
</pre>


=={{header|REXX}}==
=={{header|REXX}}==
It is more idiomatic in REXX to use sparse arrays to express a list of CSV values, especially those which have
<br>embedded blanks in them &nbsp; (or other special characters).


Most REXX interpreters use (very efficient) hashing to index sparse arrays, which is much faster than performing an
{{update|REXX|
<br>incremental (sequential) search through an indexed array.
* A third test-case (search condition) has been added to the task description.
* The code uses a hard-coded loop for each search. Consider a more generic and re-usable approach as asked for by the task description, or explain to readers why that wasn't possible or sensible in this language.
}}


Only one loop is needed to find the result for the 2nd task requirement &nbsp; (although the loop could be eliminated).
It is more idiomatic in REXX to use sparse arrays to express a list of CSV values which have embedded blanks in them.
<br>The other two task requirements are found without using traditional &nbsp; '''IF''' &nbsp; statements.


The approach taken in this REXX program makes use of a &nbsp; '''DO WHILE''' &nbsp; and &nbsp; '''DO UNTIL''' &nbsp; structure which
Most REXX interpreters use hashing to index sparse arrays, which is much faster than performing a sequential search.
<br>makes it much simpler (and idiomatic) and easier to code &nbsp; (instead of adding multiple &nbsp; '''IF''' &nbsp; statements to a
<lang rexx>/*REXX program (using criteria) finds values or indices in a list (of 2 datatypes).*/
<br>generic search routine/function).
$="Lagos=21, Cairo=15.2, Kinshasa-Brazzaville=11.3, Greater Johannesburg=7.55, Mogadishu=5.85,",

"Khartoum-Omdurman=4.98, Dar Es Salaam=4.7, Alexandria=4.58, Abidjan=4.4, Casablanca=3.98"
This REXX version does &nbsp; ''not'' &nbsp; rely on the list being sorted by population count.
@.= '(not found)' /*default value for "not found" cities.*/
<syntaxhighlight lang="rexx">/*REXX program (when using criteria) locates values (indices) from an associate array. */
w=0 /*W: used for formatting city's name. */
$="Lagos=21, Cairo=15.2, Kinshasa-Brazzaville=11.3, Greater Johannesburg=7.55, Mogadishu=5.85,",
do #=0 while $\='' /* [↓] extract all cities&populations.*/
"Khartoum-Omdurman=4.98, Dar Es Salaam=4.7, Alexandria=4.58, Abidjan=4.4, Casablanca=3.98"
parse var $ c '=' p "," $ /*destructive parse of the $ string. */
c=space(c); w=max(w, length(c) ) /*remove superfluous spaces in table. */
@.= '(city not found)'; city.= "(no city)" /*city search results for not found.*/
/* [↓] construct associate arrays. */
city.#=c; pop.#=p; pop.c=#; @.c=# /*assign city&pop──arrays; & city──►idx*/
do #=0 while $\=''; parse var $ c '=' p "," $; c=space(c); parse var c a 2; @.c=#
end /*#*/ /* [↑] TOWN. array starts at 0 index.*/
city.#=c; pop.#=p; pop.c=#; if @.a==@. then @.a=c; /*assign city, pop, indices.*/
/*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ task 1: show the ordered city list.*/
end /*#*/ /* [↑] city array starts at 0 index*/
say center('index',9,"═") center("city",w,"═") center('population (millions)',27,"═")
do j=0 for # /*get pertinent info.*/
/*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ task 1: show the INDEX of a city.*/
say center(j,9) center(city.j, w) center(pop.j, 27) /*index, city, pop. */
town= 'Dar Es Salaam' /*the name of a city for the search.*/
say 'The city of ' town " has an index of: " @.town /*show (zero─based) index of a city.*/
end /*j*/
say /*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ task 2: show 1st city whose pop<5 M*/
say
/*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ task 2: show the INDEX of a city.*/
many=5 /*size of a city's pop in millions. */
town= 'Dar Es Salaam' /*show (zero─based) index of this city.*/
do k=0 for # until pop.k<many; end /*find a city's pop from an index. */
say 'The city of ' town " has an index of: " findIndex(city); say
say '1st city that has a population less than ' many " million is: " city.k
/*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ task 3: show 1st city whose pop<5 M*/
say /*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ task 3: show 1st city with A* name.*/
many=5 /*show 1st city whose population is <5M*/
c1= 'A' /*1st character of a city for search*/
say '1st city that starts with the letter' c1 "is: " @.c1 /*stick a fork in it, all done*/</syntaxhighlight>
do k=0 for #; p=getPop(k) /*get a city's population from an index*/
if \lessPop(p, many) then iterate /*does the city fail predicate test? */
say 'The city of ' city.k " has a population less than " many ' million.'
leave /*only show the first city of pop < 5 M*/
end /*k*/
if k># then say 'no city found with a population of less than ' many " million."
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
findIndex: parse arg _; return @._ /*returns the INDEX of a city or null. */
getPop: parse arg _; return pop._ /*returns the pop of an index of city. */
lessPop: return arg(1) < arg(2) /*predicate function tests if pop < 5 M*/</lang>
'''output''' &nbsp; when using the default inputs:
'''output''' &nbsp; when using the default inputs:
<pre>
<pre>
══index══ ════════city════════ ═══population (millions)═══
0 Lagos 21
1 Cairo 15.2
2 Kinshasa-Brazzaville 11.3
3 Greater Johannesburg 7.55
4 Mogadishu 5.85
5 Khartoum-Omdurman 4.98
6 Dar Es Salaam 4.7
7 Alexandria 4.58
8 Abidjan 4.4
9 Casablanca 3.98

The city of Dar Es Salaam has an index of: 6
The city of Dar Es Salaam has an index of: 6


The city of Khartoum-Omdurman has a population less than 5 million.
1st city that has a population less than 5 million is: Khartoum-Omdurman

1st city that starts with the letter A is: Alexandria
</pre>
</pre>


=={{header|Ring}}==
=={{header|Ring}}==
<syntaxhighlight lang="ring">
# Project : Search a list of records


cities = [[:name = "Lagos",:population = 21.0 ],
{{update|Ring|
[:name = "Cairo",:population = 15.2 ],
* A third test-case (search condition) has been added to the task description.
[:name = "Kinshasa-Brazzaville",:population = 11.3 ],
* The code uses a hard-coded loop for the population<5 search. Consider a more generic approach as asked for by the task description, or explain to readers why that wasn't possible or sensible in this language.
[:name = "Greater Johannesburg",:population = 7.55],
}}
[:name = "Mogadishu",:population = 5.85],
<lang Ring>
name = 1 population = 2
[:name = "Khartoum-Omdurman",:population = 4.98],
[:name = "Dar Es Salaam",:population = 4.7 ],
cities = [
[:name = "Alexandria",:population = 4.58],
["Lagos", 21] ,
[:name = "Abidjan",:population = 4.4 ],
["Cairo", 15.2],
[:name = "Casablanca",:population = 3.98]]
["Kinshasa-Brazzaville", 11.3],
["Greater Johannesburg", 7.55],
["Mogadishu", 5.85],
["Khartoum-Omdurman", 4.98],
["Dar Es Salaam", 4.7],
["Alexandria", 4.58],
["Abidjan", 4.4],
["Casablanca", 3.98 ]
]
See find(cities,"Dar Es Salaam",name) + nl # output = 7
See cities[find(cities,4.58,population)][name] + nl # output = Alexandria
for x in cities if x[population] < 5 see x[name] + nl exit ok next # output = Khartoum-Omdurman
</lang>


for n = 1 to len(cities)
=={{header|Ruby}}==
if cities[n][:name] = "Dar Es Salaam"
see n-1 + nl
ok
next


for n = 1 to len(cities)
{{update|Ruby|
if cities[n][:population] < 5.00
* A third test-case (search condition) has been added to the task description.
see cities[n][:name] + nl
}}
exit
ok
next

for n = 1 to len(cities)
if left(cities[n][:name],1) = "A"
see cities[n][:population] + nl
exit
ok
next
</syntaxhighlight>
Output:
<pre>
6
Khartoum-Omdurman
4.58
</pre>

=={{header|Ruby}}==


<lang Ruby>cities = [
<syntaxhighlight lang="ruby">cities = [
{name: "Lagos", population: 21},
{name: "Lagos", population: 21},
{name: "Cairo", population: 15.2},
{name: "Cairo", population: 15.2},
{name: "Kinshasa-Brazzaville", population: 11.3},
{name: "Kinshasa-Brazzaville", population: 11.3},
{name: "Greater Johannesburg", population: 7.55},
{name: "Greater Johannesburg", population: 7.55},
{name: "Mogadishu", population: 5.85},
{name: "Mogadishu", population: 5.85},
{name: "Khartoum-Omdurman", population: 4.98},
{name: "Khartoum-Omdurman", population: 4.98},
{name: "Dar Es Salaam", population: 4.7},
{name: "Dar Es Salaam", population: 4.7},
{name: "Alexandria", population: 4.58},
{name: "Alexandria", population: 4.58},
{name: "Abidjan", population: 4.4},
{name: "Abidjan", population: 4.4},
{name: "Casablanca", population: 3.98}
{name: "Casablanca", population: 3.98},
]
]


puts cities.index{|city| city[:name] == "Dar Es Salaam"} # => 6
puts cities.index{|city| city[:name] == "Dar Es Salaam"} # => 6
puts cities.find {|city| city[:population] < 5.0}[:name] # => Khartoum-Omdurman </lang>
puts cities.find {|city| city[:population] < 5.0}[:name] # => Khartoum-Omdurman
puts cities.find {|city| city[:name][0] == "A"}[:population] # => 4.58
</syntaxhighlight>


=={{header|Sidef}}==
=={{header|Rust}}==
<syntaxhighlight lang="rust">struct City {
name: &'static str,
population: f64,
}


fn main() {
{{update|Sidef|
let cities = [
* A third test-case (search condition) has been added to the task description.
City {
}}
name: "Lagos",
population: 21.0,
},
City {
name: "Cairo",
population: 15.2,
},
City {
name: "Kinshasa-Brazzaville",
population: 11.3,
},
City {
name: "Greater Johannesburg",
population: 7.55,
},
City {
name: "Mogadishu",
population: 5.85,
},
City {
name: "Khartoum-Omdurman",
population: 4.98,
},
City {
name: "Dar Es Salaam",
population: 4.7,
},
City {
name: "Alexandria",
population: 4.58,
},
City {
name: "Abidjan",
population: 4.4,
},
City {
name: "Casablanca",
population: 3.98,
},
];

println!(
"{:?}",
cities.iter().position(|city| city.name == "Dar Es Salaam")
);
println!(
"{:?}",
cities
.iter()
.find(|city| city.population < 5.0)
.map(|city| city.name)
);
println!(
"{:?}",
cities
.iter()
.find(|city| city.name.starts_with('A'))
.map(|city| city.population)
);
}
</syntaxhighlight>
{{Out}}
<pre>Some(6)
Some("Khartoum-Omdurman")
Some(4.58)</pre>

=={{header|Scala}}==
{{Out}}See it in running in your browser by [https://scalafiddle.io/sf/8OlRzf8/0 ScalaFiddle (JavaScript executed in browser)] or by [https://scastie.scala-lang.org/fGhNDUNHRqq8h04x3Mm2Kw Scastie (remote JVM)].
<syntaxhighlight lang="scala">object SearchListOfRecords extends App {
val cities = Vector(
City("Lagos", 21.0e6),
City("Cairo", 15.2e6),
City("Kinshasa-Brazzaville", 11.3e6),
City("Greater Johannesburg", 7.55e6),
City("Mogadishu", 5.85e6),
City("Khartoum-Omdurman", 4.98e6),
City("Dar Es Salaam", 4.7e6),
City("Alexandria", 4.58e6),
City("Abidjan", 4.4e6),
City("Casablanca", 3.98e6)
)

def index = cities.indexWhere((_: City).name == "Dar Es Salaam")

def name = cities.find(_.pop < 5.0e6).map(_.name)

def pop = cities.find(_.name(0) == 'A').map(_.pop)

case class City(name: String, pop: Double)

println(
s"Index of first city whose name is 'Dar Es Salaam' = $index\n" +
s"Name of first city whose population is less than 5 million = ${name.get}\n" +
f"Population of first city whose name starts with 'A' = ${pop.get}%,.0f")

}</syntaxhighlight>
{{Out}}
<pre>Index of first city whose name is 'Dar Es Salaam' = 6
Name of first city whose population is less than 5 million = Khartoum-Omdurman
Population of first city whose name starts with 'A' = 4,580,000</pre>

=={{header|Scheme}}==
{{libheader|Scheme/SRFIs}}

High-level functions for finding items in lists are provided by the (srfi 1) library:

* (find pred? list) returns the first item matching the given pred? function, or #f if none match
* (list-index pred? list) is similar but returns the index of the match (or #f)

The predicate can be used to pick out the part of a compound structure we want to find.

In a similar way (srfi 132) provides sorting routines with user-defined predicates: one is illustrated to ensure the list of items is sorted in decreasing population order.

<syntaxhighlight lang="scheme">
(import (scheme base)
(scheme char)
(scheme write)
(srfi 1) ; lists
(srfi 132)) ; sorting

(define-record-type <places> ; compound data type is a record with two fields
(make-place name population)
place?
(name place-name)
(population place-population))

(define *items*
(list-sort ; sort by decreasing population
(lambda (r1 r2) (> (place-population r1)
(place-population r2)))
(list (make-place "Lagos" 21.0)
(make-place "Cairo" 15.2)
(make-place "Kinshasa-Brazzaville" 11.3)
(make-place "Greater Johannesburg" 7.55)
(make-place "Mogadishu" 5.85)
(make-place "Khartoum-Omdurman" 4.98)
(make-place "Dar Es Salaam" 4.7)
(make-place "Alexandria" 4.58)
(make-place "Abidjan" 4.4)
(make-place "Casablanca" 3.98))))

;; Find the (zero-based) index of the first city in the list
;; whose name is "Dar Es Salaam"
(display "Test 1: ")
(display (list-index (lambda (item)
(string=? "Dar Es Salaam" (place-name item)))
*items*))
(newline)

;; Find the name of the first city in this list
;; whose population is less than 5 million
(display "Test 2: ")
(display (place-name
(find (lambda (item)
(< (place-population item) 5.0))
*items*)))
(newline)

;; Find the population of the first city in this list
;; whose name starts with the letter "A"
(display "Test 3: ")
(display (place-population
(find (lambda (item)
(char=? (string-ref (place-name item) 0)
#\A))
*items*)))
(newline)
</syntaxhighlight>

{{out}}
<pre>
Test 1: 6
Test 2: Khartoum-Omdurman
Test 3: 4.58
</pre>

=={{header|Sidef}}==


<lang ruby>struct City {
<syntaxhighlight lang="ruby">struct City {
String name,
String name,
Number population,
Number population,
Line 832: Line 3,387:
]
]


say cities.index{|city| city.name == "Dar Es Salaam"} # => 6
say cities.index{|city| city.name == "Dar Es Salaam"}
say cities.first{|city| city.population < 5.0}.name # => Khartoum-Omdurman</lang>
say cities.first{|city| city.population < 5.0}.name
say cities.first{|city| city.name.begins_with("A")}.population</syntaxhighlight>


=={{header|Tcl}}==
{{out}}
<pre>
6
Khartoum-Omdurman
4.58
</pre>


=={{header|SQL}}==
{{update|Tcl|
I probably wrote the C implementation for this problem. It has been quite some time, anyways, I got a notification that this page has been edited and while browsing it on my phone I found that this most database worthy of problems doesn't have a SQL implementation. Thus even after a long day, I logged back in again, to rosettacode, not work.
* A third test-case (search condition) has been added to the task description.

* You should mention to readers that the bisect example relies in the list being sorted.
I am kind of fond of SQL, I am not a DBA but wanted to be one when I started my career. Databases are among the few things I still hold in respect :)
* You should explain to readers why you deviated from the data structure in the task description by making the records positional (index-based) instead of associative (key-based).

}}
Credits : This wouldn't have been possible without https://sqliteonline.com , you can create your own tables and run queries on them without installing your own DB. The queries below should work on most DBs but some like Access ( is that really a DB ? ) doesn't have LIMIT, or so I read.

But to get started, first we create the table :

PS : I realised after posting this implementation that not all cities in this list are capitals, well, it was a long day :P

<syntaxhighlight lang="sql">
create table african_capitals(name varchar2(100), population_in_millions number(3,2));
</syntaxhighlight>

Then we load the data :

<syntaxhighlight lang="sql">
insert into african_capitals values("Lagos", 21.0);
insert into african_capitals values("Cairo",15.2);
insert into african_capitals values("Kinshasa-Brazzaville",11.3);
insert into african_capitals values("Greater Johannesburg",7.55);
insert into african_capitals values("Mogadishu",5.85);
insert into african_capitals values("Khartoum-Omdurman",4.98);
insert into african_capitals values("Dar Es Salaam",4.7);
insert into african_capitals values("Alexandria",4.58);
insert into african_capitals values("Abidjan",4.4);
insert into african_capitals values("Casablanca",3.98);
</syntaxhighlight>

If you are using sqliteonline.com, run the select query below to inspect your data :

<syntaxhighlight lang="sql">
select * from african_capitals;
</syntaxhighlight>

Now we are ready to fire the queries to solve the problem statements, one note though : DB tables are 1 indexed, hence the capital of Tanzania is the 7th item, not 6th as is the case for C and it's vast family.

<syntaxhighlight lang="sql">
with temp as(select name,row_number() over() as rownum from african_capitals) select rownum from temp where name="Dar Es Salaam";
</syntaxhighlight>

{{Output}}
<pre>
7
</pre>

The LIMIT keyword in the 2nd and 3rd queries is not supported by all DBs, it works on Oracle and SQLite though

<syntaxhighlight lang="sql">
select name from african_capitals where population_in_millions < 5 limit 1;
</syntaxhighlight>

{{Output}}
<pre>
Khartoum-Omdurman
</pre>

<syntaxhighlight lang="sql">
select population_in_millions from african_capitals where name like "A%" limit 1;
</syntaxhighlight>

{{Output}}
<pre>
4.58
</pre>

=={{header|Standard ML}}==

<syntaxhighlight lang="sml">type city = { name : string, population : real }

val citys : city list = [
{ 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 } ]

val firstCityi = #1 (valOf (List.findi (fn (_, city) => #name(city) = "Dar Es Salaam") citys))
val firstBelow5M = #name (valOf (List.find (fn city => #population(city) < 5.0) citys))
val firstPopA = #population (valOf (List.find (fn city => String.substring (#name(city), 0, 1) = "A") citys))</syntaxhighlight>

{{Output}}
<pre>val firstCityi = 6 : int
val firstBelow5M = "Khartoum-Omdurman" : string
val firstPopA = 4.58 : real</pre>

=={{header|Swift}}==


Data:
Tcl's <tt>[http://wiki.tcl.tk/1486 lsearch]</tt> command takes many useful options. This task illustrates the <tt>-index</tt> and <tt>-bisect</tt> options.


<syntaxhighlight lang="swift">struct Place {
<lang Tcl>set cities {
var name: String
{"Lagos" 21}
var population: Double
{"Cairo" 15.2}
{"Kinshasa Brazzaville" 11.3}
{"Greater Johannesburg" 7.55}
{"Mogadishu" 5.85}
{"Khartoum Omdurman" 4.98}
{"Dar Es Salaam" 4.7}
{"Alexandria" 4.58}
{"Abidjan" 4.4}
{"Casablanca" 3.98}
}
}
puts "Dar Es Salaam is at position: [
lsearch -index 0 $cities "Dar Es Salaam"
]."


let places = [
set cities_by_size [
Place(name: "Lagos", population: 21.0),
lsort -index 1 -real $cities
Place(name: "Cairo", population: 15.2),
]
Place(name: "Kinshasa-Brazzaville", population: 11.3),
Place(name: "Greater Johannesburg", population: 7.55),
Place(name: "Mogadishu", population: 5.85),
Place(name: "Khartoum-Omdurman", population: 4.98),
Place(name: "Dar Es Salaam", population: 4.7),
Place(name: "Alexandria", population: 4.58),
Place(name: "Abidjan", population: 4.4),
Place(name: "Casablanca", population: 3.98)
]</syntaxhighlight>


===Using built-in methods===
puts "The largest city of < 5m is: [

lsearch -inline -index 1 -bisect -real $cities_by_size 5.0
<syntaxhighlight lang="swift">guard let salaamI = places.firstIndex(where: { $0.name == "Dar Es Salaam" }) else {
]"</lang>
fatalError()
}

print("Dar Es Salaam has index: \(salaamI)")

guard let lessThan5 = places.first(where: { $0.population < 5 }) else {
fatalError()
}

print("First city with less than 5mil population: \(lessThan5.name)")

guard let startsWithA = places.first(where: { $0.name.hasPrefix("A") }) else {
fatalError()
}

print("Population of first city starting with A: \(startsWithA.population)")</syntaxhighlight>


{{out}}
{{out}}

<pre>Dar Es Salaam is at position: 6.
<pre>Dar Es Salaam has index: 6
The largest city of < 5m is: "Khartoum Omdurman" 4.98
First city with less than 5mil population: Khartoum-Omdurman
Population of first city starting with A: 4.58</pre>

===Custom method using Key Paths===

<syntaxhighlight lang="swift">extension Collection {
func firstIndex<V: Equatable>(
withProperty prop: KeyPath<Element, V>,
_ op: (V, V) -> Bool,
_ val: V
) -> Index? {
for i in indices where op(self[i][keyPath: prop], val) {
return i
}

return nil
}
}

guard let salaamI = places.firstIndex(withProperty: \.name, ==, "Dar Es Salaam") else {
fatalError()
}

print("Dar Es Salaam has index: \(salaamI)")

guard let lessThan5I = places.firstIndex(withProperty: \.population, <, 5) else {
fatalError()
}

print("First city with less than 5mil population: \(places[lessThan5I].name)")

guard let aI = places.firstIndex(withProperty: \.name, { $0.hasPrefix($1) }, "A") else {
fatalError()
}

print("Population of first city starting with A: \(places[aI].population)")</syntaxhighlight>

{{out}}

Same as first method

=={{header|Tcl}}==
<syntaxhighlight lang="tcl"># records is a list of dicts.
set records {
{ 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 }
}

# Tcl's version of "higher order programming" is a bit unusual. Instead of passing lambda
# functions, it is often easier to pass script fragments. This command takes two such
# arguments: $test is an expression (as understood by [expr]), and $action is a script.
# thanks to [dict with], both $test and $action can refer to the fields of the current
# record by name - or to other variables used in the proc, like $index or $record.
proc search {records test action} {
set index 0
foreach record $records {
dict with record {}
if $test $action
incr index
}
error "No match found!"
}

# Find the (zero-based) index of the first city in the list whose name is "Dar Es Salaam"
puts [search $records {$name eq "Dar Es Salaam"} {return $index}]
# Find the name of the first city in this list whose population is less than 5 million
puts [search $records {$population < 5.0} {return $name}]
# Find the population of the first city in this list whose name starts with the letter "A"
puts [search $records {[string match A* $name]} {return $population}]
</syntaxhighlight>

{{out}}
<pre>6
Khartoum-Omdurman
4.58</pre>

=={{header|V (Vlang)}}==
<syntaxhighlight lang="Zig">
const cities = {"Lagos": 21.0, "Cairo": 15.2, "Kinshasa-Brazzaville": 11.3, "Greater Johannesburg": 7.55, "Mogadishu": 5.85, "Khartoum-Omdurman": 4.98, "Dar Es Salaam": 4.7, "Alexandria": 4.58, "Abidjan": 4.4, "Casablanca": 3.98}

fn main() {
mut count := 0
mut result :=""
for city, population in cities {
count++
if city == "Dar Es Salaam" {
if !result.contains("Index") {result += "Index of '${city}': ${count - 1}\n"}
}
if population < 5 {
if !result.contains("million") {result += "First city with less than 5 million: ${city}\n"}
}
if city[0].ascii_str() == "A" {
if !result.contains("letter") {result += "First population that starts with letter 'A': ${population}\n"}
}
}
println(result.all_before_last("\n"))
}
</syntaxhighlight>

{{out}}
<pre>
First city with less than 5 million: Khartoum-Omdurman
Index of 'Dar Es Salaam': 6
First population that starts with letter 'A': 4.58
</pre>
</pre>


=={{header|zkl}}==
=={{header|Wren}}==
{{libheader|Wren-dynamic}}
<syntaxhighlight lang="wren">import "./dynamic" for Tuple


var Element = Tuple.create("Element", ["record", "index"])
{{update||
* A third test-case (search condition) has been added to the task description.
}}


var findFirst = Fn.new { |seq, pred|
<lang zkl>list:=T(SD("name","Lagos", "population",21), SD("name","Cairo", "population",15.2), SD("name","Kinshasa-Brazzaville", "population",11.3), SD("name","Greater Johannesburg", "population",7.55), SD("name","Mogadishu", "population",5.85), SD("name","Khartoum-Omdurman", "population",4.98), SD("name","Dar Es Salaam", "population",4.7), SD("name","Alexandria", "population",4.58), SD("name","Abidjan", "population",4.4), SD("name","Casablanca", "population",3.98));
var i = 0
for (e in seq) {
if (pred.call(e)) return Element.new(e, i)
i = i + 1
}
return Element.new(null, -1)
}


var City = Tuple.create("City", ["name", "pop"])
n:=list.filter1n(fcn(city){ city["name"]=="Dar Es Salaam" });
// or city["name"].matches("dar es salaam") for case insensitive wild card match
n.println(" == index of ",list[n].values);


var cities = [
city:=list.filter1(fcn(city){ city["population"]<5 });
City.new("Lagos", 21.0),
city.values.println(" is the first city with population under 5 million.");
City.new("Cairo", 15.2),
list.filter(fcn(city){ city["population"]<5.0 }).apply("get","name").println();
City.new("Kinshasa-Brazzaville", 11.3),
list.filterNs(fcn(city){ city["population"]<5.0 }).println();
City.new("Greater Johannesburg", 7.55),
City.new("Mogadishu", 5.85),
City.new("Khartoum-Omdurman", 4.98),
City.new("Dar Es Salaam", 4.7),
City.new("Alexandria", 4.58),
City.new("Abidjan", 4.4),
City.new("Casablanca", 3.98)
]

var index = findFirst.call(cities) { |c| c.name == "Dar Es Salaam" }.index
System.print("Index of the first city whose name is 'Dar Es Salaam' is %(index).")
var city = findFirst.call(cities) { |c| c.pop < 5 }.record.name
System.print("First city whose population is less than 5 million is %(city).")
var pop = findFirst.call(cities) { |c| c.name[0] == "A" }.record.pop
System.print("The population of the first city whose name begins with 'A' is %(pop).")</syntaxhighlight>

{{out}}
<pre>
Index of the first city whose name is 'Dar Es Salaam' is 6.
First city whose population is less than 5 million is Khartoum-Omdurman.
The population of the first city whose name begins with 'A' is 4.58.
</pre>

=={{header|zkl}}==
<syntaxhighlight lang="zkl">list:=T(SD("name","Lagos", "population",21.0), // SD is a fixed dictionary
SD("name","Cairo", "population",15.2),
SD("name","Kinshasa-Brazzaville", "population",11.3),
SD("name","Greater Johannesburg", "population", 7.55),
SD("name","Mogadishu", "population", 5.85),
SD("name","Khartoum-Omdurman", "population", 4.98),
SD("name","Dar Es Salaam", "population", 4.7),
SD("name","Alexandria", "population", 4.58),
SD("name","Abidjan", "population", 4.4),
SD("name","Casablanca", "population", 3.98));


// Test case 1:
list.filter1n(fcn(city){ city["name"]=="alexandra" }).println();</lang>
n:=list.filter1n(fcn(city){ city["name"]=="Dar Es Salaam" }); // one way
where a SD is a small read only dictionary and filter1 is a filter that stops at the first match (returning the matched item), filter1N is the same but returns the index. Both filter methods return False on failure.
n:=list.filter1n(fcn(city){ city["name"].matches("dar es salaam") }); // or this way
n.println("==index of ",list[n].values);


// Test case 2:
Note that the dictionarys contain either int or float values and the filter could use either int or float (in this case, the 5 is converted to the type in the dictionary).
city:=list.filter1(fcn(city){ city["population"]<5.0 }); // stop after first match
city["name"].println(" is the first city with population under 5 million.");


// Test case 3:
The YAJL library could be used to parse the JSON data directly.
city:=list.filter1(fcn(city){ city["name"][0]=="A" });
println("The first \"A*\" city (%s) with population under 5 million: %f".fmt(city.values.xplode()));</syntaxhighlight>
where a SD is a small read only dictionary and filter1 is a filter that stops at the first match (returning the matched item). The filter method returns False on failure.
The YAJL library could be used to parse the JSON data directly (eg if the data is from the web).
{{out}}
{{out}}
<pre>
<pre>
6 == index of L("Dar Es Salaam",4.7)
6==index of L("Dar Es Salaam",4.7)
L("Khartoum-Omdurman",4.98) is the first city with population under 5 million.
Khartoum-Omdurman is the first city with population under 5 million.
The first "A*" city (Alexandria) with population under 5 million: 4.580000
L("Khartoum-Omdurman","Dar Es Salaam","Alexandria","Abidjan","Casablanca")
L(5,6,7,8,9)
False
</pre>
</pre>

Latest revision as of 20:47, 4 April 2024

Task
Search a list of records
You are encouraged to solve this task according to the task description, using any language you may know.

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?

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:

  1. The list to search through.
  2. 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

11l

T City
   String name
   Float population

   F (name, population)
      .name = name
      .population = population

V cities = [
        City(‘Lagos’, 21),
        City(‘Cairo’, 15.2),
        City(‘Kinshasa-Brazzaville’, 11.3),
        City(‘Greater Johannesburg’, 7.55),
        City(‘Mogadishu’, 5.85),
        City(‘Khartoum-Omdurman’, 4.98),
        City(‘Dar Es Salaam’, 4.7),
        City(‘Alexandria’, 4.58),
        City(‘Abidjan’, 4.4),
        City(‘Casablanca’, 3.98)
    ]

F first_index(cities, condition)
   L(city) cities
      I condition(city)
         R L.index

F first(cities, condition)
   L(city) cities
      I condition(city)
         R city

print(first_index(cities, city -> city.name == ‘Dar Es Salaam’))
print(first(cities, city -> city.population < 5.0).name)
print(first(cities, city -> city.name[0] == ‘A’).population)
Output:
6
Khartoum-Omdurman
4.58

8086 Assembly

Task-Specific Solution

This solution answers the questions as asked, and only those asked - it won't answer an arbitrary question regarding the list. All I/O subroutines that involve printing the results were left unimplemented to keep this entry brief.

	.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
Output:
06
Khartoum-Omdurman
4.58

8th

8th uses JSON as its native data representation, so using it is quite natural:

[
  { "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 }
] var, cities-raw

"Index of first occurrence of 'Dar Es Salaam': " .
"Dar Es Salaam" >r cities-raw @ 
(
  "name" m:@ r@ s:= if
    drop . cr ;;
  then
  2drop
) a:each drop rdrop

"The name of the first city in this list whose population is less than 5 million: " . 
5 >r cities-raw @ 
(
  nip
  "population" m:@ r@ n:< if
    "name" m:@ . cr break
  then
  drop
) a:each drop rdrop

"The population of the first city in this list whose name starts with the letter \"A\": " .
'A >r cities-raw @ 
(
  nip
  "name" m:@ 0 s:@ r@ n:= if
    drop "population" m:@ . cr break
  then
  2drop
) a:each drop rdrop

bye
Output:
Index of first occurrence of 'Dar Es Salaam': 6
The name of the first city in this list whose population is less than 5 million: Khartoum-Omdurman
The population of the first city in this list whose name starts with the letter "A": 4.58000

Action!

INCLUDE "D2:REAL.ACT" ;from the Action! Tool Kit

DEFINE PTR="CARD"
DEFINE ENTRY_SIZE="4"
DEFINE STX="$8E"
DEFINE STA="$8D"
DEFINE JSR="$20"
DEFINE RTS="$60"

TYPE City=[
  CARD
    name, ;CHAR ARRAY
    population] ;REAL POINTER

BYTE ARRAY cities(100)
BYTE count=[0]

CHAR ARRAY nameParam ;param for name predicate
REAL popParam ;param for population predicate
CHAR letterParam ;param for letter predicate
CITY POINTER c ;city used in predicates and actions
BYTE index ;index of city used in index action

PTR FUNC GetItemAddr(BYTE index)
  PTR addr

  addr=cities+index*ENTRY_SIZE
RETURN (addr)

PROC Append(CHAR ARRAY n REAL POINTER p)
  City POINTER dst

  dst=GetItemAddr(count)
  dst.name=n
  dst.population=p
  count==+1
RETURN

PROC InitData()
  REAL lg,ca,ki,gr,mo,kh,da,al,ab,cs

  ValR("21.0",lg) ValR("15.2",ca)
  ValR("11.3",ki) ValR("7.53",gr)
  ValR("5.85",mo) ValR("4.98",kh)
  ValR("4.7",da)  ValR("4.58",al)
  ValR("4.4",ab)  ValR("3.98",cs)

  Append("Lagos",lg)
  Append("Cairo",ca)
  Append("Kinshasa-Brazzaville",ki)
  Append("Greater Johannesburg",gr)
  Append("Mogadishu",mo)
  Append("Khartoum-Omdurman",kh)
  Append("Dar Es Salaam",da)
  Append("Alexandria",al)
  Append("Abidjan",ab)
  Append("Casablanca",cs)
RETURN

BYTE FUNC NameEquals()
RETURN (SCompare(c.name,nameParam)+1)

BYTE FUNC PopulationLess()
  REAL diff
  BYTE ARRAY x

  RealSub(popParam,c.population,diff)
  x=diff
  IF (x(0)&$80)=$00 THEN
    RETURN (1)
  FI
RETURN (0)

BYTE FUNC FirstLetter()
  CHAR ARRAY n

  n=c.name
  IF n(0)>=1 AND n(1)=letterParam THEN
    RETURN (1)
  FI
RETURN (0)

;jump addr is stored in X and A registers
BYTE FUNC Predicate=*(PTR jumpAddr)
 [STX Predicate+8
  STA Predicate+7
  JSR $00 $00
  RTS]

PROC PrintIndex()
  PrintF("index=%I%E",index)
RETURN

PROC PrintName()
  PrintF("name=%S%E",c.name)
RETURN

PROC PrintPopulation()
  Print("population=")
  PrintRE(c.population)
RETURN

;jump addr is stored in X and A registers
PROC Action=*(PTR jumpAddr)
  [STX Action+8
   STA Action+7
   JSR $00 $00
   RTS]

PROC Find(PTR predicateFun,actionFun)
  FOR index=0 TO count-1
  DO
    c=GetItemAddr(index)
    IF Predicate(predicateFun) THEN
      Action(actionFun)
      EXIT
    FI
  OD
RETURN

PROC Main()
  Put(125) PutE() ;clear screen
  InitData()

  nameParam="Dar Es Salaam"
  Find(NameEquals,PrintIndex)

  ValR("5.0",popParam)
  Find(PopulationLess,PrintName)

  letterParam='A
  Find(FirstLetter,PrintPopulation)
RETURN
Output:

Screenshot from Atari 8-bit computer

index=6
name=Khartoum-Omdurman
population=4.58

Ada

This solution in inspired by how the Ada.Containers child packages work. Usually a Cursor contains two accesses: one to the container and one to the element. Since we want to get the index of the element as well, the index was stored instead.

Works with: Ada version 2005
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with Ada.Text_IO;

procedure Search_A_List_Of_Records
is
   function "+"(input : in String) return Unbounded_String renames To_Unbounded_String;
   function "+"(input : in Unbounded_String) return String renames To_String;

   type City is record
      name : Unbounded_String;
      population : Float;
   end record;

   type City_Array is array(Positive range <>) of City;
   type City_Array_Access is access City_Array;

   type Cursor is record
      container : City_Array_Access;
      index : Natural;
   end record;

   function Element(C : in Cursor) return City is
   begin
      if C.container = null or C.index = 0 then
         raise Constraint_Error with "No element.";
      end if;

      return C.container.all(C.index);
   end Element;

   function Index_0(C : in Cursor) return Natural is
   begin
      if C.container = null or C.index = 0 then
         raise Constraint_Error with "No element.";
      end if;

      return C.index - C.container.all'First;
   end Index_0;

   function Find
     (container : in City_Array;
      check : not null access function(Element : in City) return Boolean)
      return Cursor
   is
   begin
      for I in container'Range loop
         if check.all(container(I)) then
            return (new City_Array'(container), I);
         end if;
      end loop;
      return (null, 0);
   end;

   function Dar_Es_Salaam(Element : in City) return Boolean is
   begin
      return Element.name = "Dar Es Salaam";
   end Dar_Es_Salaam;

   function Less_Than_Five_Million(Element : in City) return Boolean is
   begin
      return Element.population < 5.0;
   end Less_Than_Five_Million;

   function Starts_With_A(Item : in City) return Boolean is
   begin
      return Element(Item.name, 1) = 'A';
   end Starts_With_A;

   cities : constant City_Array :=
     ((+"Lagos",                21.0),
      (+"Cairo",                15.2),
      (+"Kinshasa-Brazzaville", 11.3),
      (+"Greater Johannesburg", 7.55),
      (+"Mogadishu",            5.85),
      (+"Khartoum-Omdurman",    4.98),
      (+"Dar Es Salaam",        4.7 ),
      (+"Alexandria",           4.58),
      (+"Abidjan",              4.4 ),
      (+"Casablanca",           3.98));
begin
   Ada.Text_IO.Put_Line(Index_0(Find(cities, Dar_Es_Salaam'Access))'Img);
   Ada.Text_IO.Put_Line(+Element(Find(cities, Less_Than_Five_Million'Access)).name);
   Ada.Text_IO.Put_Line(Element(Find(cities, Starts_With_A'Access)).population'Img);
end Search_A_List_Of_Records;
Output:
 6
Khartoum-Omdurman
 4.58000E+00

ALGOL 68

# Algol 68 doesn't have generic array searches but we can easily provide #
# type specific ones                                                     #

# mode to hold the city/population info #
MODE CITYINFO = STRUCT( STRING name, REAL population in millions );

# array of cities and populations #
[ 1 : 10 ]CITYINFO cities := ( ( "Lagos",                21.0 )
                             , ( "Cairo",                15.2 )
                             , ( "Kinshasa-Brazzaville", 11.3 )
                             , ( "Greater Johannesburg", 7.55 )
                             , ( "Mogadishu",            5.85 )
                             , ( "Khartoum-Omdurman",    4.98 )
                             , ( "Dar Es Salaam",        4.7  )
                             , ( "Alexandria",           4.58 )
                             , ( "Abidjan",              4.4  )
                             , ( "Casablanca",           3.98 )
                             );

# operator to find the first city with the specified criteria, expressed as a procedure #
# returns the index of the CITYINFO. We can also overload FIND so it can be applied to  #
# arrays of other types                                                                 #
# If there is no city matching the criteria, a value greater than the upper bound of    #
# the cities array is returned                                                          #
PRIO FIND = 1;
OP   FIND = ( REF[]CITYINFO cities, PROC( REF CITYINFO )BOOL criteria )INT:
     BEGIN
         INT  result := UPB cities + 1;
         BOOL found  := FALSE;
         FOR pos FROM LWB cities TO UPB cities WHILE NOT found DO
             IF criteria( cities[ pos ] )
             THEN
                 found  := TRUE;
                 result := pos
             FI
         OD;
         result
     END # FIND # ;

# convenience operator to determine whether a STRING starts with a particular character #
# returns TRUE if s starts with c, FALSE otherwise                                      #
PRIO STARTSWITH = 9;
OP   STARTSWITH = ( STRING s, CHAR c )BOOL:
     IF LWB s > UPB s THEN FALSE # empty string                                         #
     ELSE s[ LWB s ] = c
     FI # STARTSWITH # ;

# find the 0-based index of Dar Es Salaam #
# ( if we remove the "[ @ 0 ]", it would find the 1-based index ) #
# NB - this assumes there is one - would get a subscript bound error if there isn't #
print( ( "index of Dar Es Salaam (from 0): "
       , whole( cities[ @ 0 ] FIND ( ( REF CITYINFO city )BOOL: name OF city = "Dar Es Salaam" ), 0 )
       , newline
       )
     );

# find the first city with population under 5M #
# NB - this assumes there is one - would get a subscript bound error if there isn't #
print( ( name OF cities[ cities FIND ( ( REF CITYINFO city )BOOL: population in millions OF city < 5.0 ) ]
       , " has a population under 5M"
       , newline
       )
     );

# find the population of the first city whose name starts with "A" #
# NB - this assumes there is one - would get a subscript bound error if there isn't #
print( ( "The population of a city named ""A..."" is: "
       , fixed( population in millions OF cities[ cities FIND ( ( REF CITYINFO city )BOOL: name OF city STARTSWITH "A" ) ], 0, 2 )
       , newline
       )
     )
Output:
index of Dar Es Salaam (from 0): 6
Khartoum-Omdurman has a population under 5M
The population of a city named "A..." is: 4.58

AppleScript

Translation of: JavaScript
-- RECORDS

property lstCities : [¬
    {|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}]


-- SEARCHES

-- nameIsDar :: Record -> Bool
on nameIsDar(rec)
    |name| of rec = "Dar Es Salaam"
end nameIsDar

-- popBelow :: Record -> Bool
on popBelow5M(rec)
    population of rec < 5
end popBelow5M

-- nameBeginsWith :: Record -> Bool
on nameBeginsWithA(rec)
    text 1 of |name| of rec = "A"
end nameBeginsWithA


-- TEST
on run
    
    return {¬
        findIndex(nameIsDar, lstCities), ¬
        ¬
            |name| of find(popBelow5M, lstCities), ¬
        ¬
            population of find(nameBeginsWithA, lstCities)}
    
end run




-- GENERIC FUNCTIONS

-- find :: (a -> Bool) -> [a] -> Maybe a
on find(f, xs)
    tell mReturn(f)
        set lng to length of xs
        repeat with i from 1 to lng
            if lambda(item i of xs) then return item i of xs
        end repeat
        return missing value
    end tell
end find

-- findIndex :: (a -> Bool) -> [a] -> Maybe Int
on findIndex(f, xs)
    tell mReturn(f)
        set lng to length of xs
        repeat with i from 1 to lng
            if lambda(item i of xs) then return i
        end repeat
        return missing value
    end tell
end findIndex

-- Lift 2nd class handler function into 1st class script wrapper 
-- mReturn :: Handler -> Script
on mReturn(f)
    if class of f is script then
        f
    else
        script
            property lambda : f
        end script
    end if
end mReturn
Output:
{6, "Khartoum-Omdurman", 4.58}

AppleScriptObjectiveC

While vanilla AppleScript doesn't provide filters for its own lists and records (and, by the way, has never officially supported square-bracket lists like the one used in the script above), its extension AppleScriptObjectiveC can filter the equivalent Foundation classes. So bridging between the classes may occasionally be useful. For efficiency, one would try to avoid repeatedly bridging the same objects.

use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"

-- Return the zero-based index of the first dictionary in an array which matches a given criterion or criteria.
on indexOfFirstDictionaryInArray:theArray |whose|:predicateText
    set filter to current application's class "NSPredicate"'s predicateWithFormat:(predicateText)
    set filteredArray to theArray's filteredArrayUsingPredicate:(filter)
    if ((count filteredArray) > 0) then
        return (theArray's indexOfObjectIdenticalTo:(filteredArray's firstObject())) as integer
    else
        return missing value -- No match.
    end if
end indexOfFirstDictionaryInArray:|whose|:

on run
    local listOfRecords, arrayOfDictionaries, result1, result2, result3
    
    set listOfRecords to {¬
        {|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}}
    
    set arrayOfDictionaries to current application's class "NSArray"'s arrayWithArray:(listOfRecords)
    
    set result1 to my indexOfFirstDictionaryInArray:arrayOfDictionaries |whose|:"name == 'Dar Es Salaam'"
    
    set result2 to my indexOfFirstDictionaryInArray:arrayOfDictionaries |whose|:"population < 5"
    if (result2 is not missing value) then set result2 to |name| of item (result2 + 1) of listOfRecords
    
    set result3 to my indexOfFirstDictionaryInArray:arrayOfDictionaries |whose|:"name BEGINSWITH 'A'"
    if (result3 is not missing value) then set result3 to population of item (result3 + 1) of listOfRecords
    
    return {result1, result2, result3} --> {6, "Khartoum-Omdurman", 4.58}
end run

Arturo

; by @Krenium

define :city [name population][]

records: map [
    ["Lagos" 21.0]
    ["Cairo" 15.2]
    ["Kinshasa-Brazzaville" 11.3]
    ["Greater Johannesburg" 7.55]
    ["Mogadishu" 5.85]
    ["Khartoum-Omdurman" 4.98]
    ["Dar Es Salaam" 4.7]
    ["Alexandria" 4.58]
    ["Abidjan" 4.4]
    ["Casablanca" 3.98]
] => [to :city &]

find: function [block f][
    loop.with: 'i block 'elt [
        if f elt -> return @[elt i]        
    ]
    return false
]

; Print the index of the first city named Dar Es Salaam.
print last find records $[c][equal? c\name "Dar Es Salaam"]

; Print the name of the first city with under 5 million people.
print get first find records $[c][less? c\population 5] 'name

; Print the population of the first city starting with 'A'.
print get first find records $[c][equal? first c\name `A`] 'population
Output:
6
Khartoum-Omdurman
4.58

BASIC

Commodore BASIC

C= BASIC has no associative data structure, so this just uses a two-dimensional array. It is written to accept a dynamically-sized list of cities and populations, with an empty-string sentinel indicating the end of the list. It also uses a form of pseudo-higher-order programming: the search function uses the query function `FNQ`, which is redefined by the caller to match the desired criteria for each test.

Note that in text mode (upper/lowercase), BASIC keywords are only recognized in lowercase.

100 nc=0
110 read n$
120 if n$="" then 160
130 read p$
140 nc=nc+1
150 goto 110
160 restore
170 dim ci$(nc-1,1)
180 for i=0 to nc-1
190 : for j=0 to 1
200 :  read ci$(i,j)
210 : next j
220 next i
230 :
240 print chr$(14);:rem text mode
250 print: print "Test 1. name='Dar Es Salaam':"
260 rem search uses query function fnq 
270 def fnq(i) = ci$(i,0) = "Dar Es Salaam"
280 gosub 500
290 if i<0 then print "  None found.":goto 310
300 print "  Index="i"."
310 print: print "Test 2. population < 5M:"
320 def fnq(i) = val(ci$(i,1)) < 5
330 gosub 500
340 if i<0 then print "  None found.":goto 360
350 print "  Name="ci$(i,0)"."
360 print: print "Test 3. name like 'A%':"
370 def fnq(i) = left$(ci$(i,0),1)="A"
380 gosub 500
390 if i<0 then print "  None found.":goto 410
400 print "  Population="ci$(i,1)"."
410 end
420 :
500 for i=0 to nc-1 
510 : if fnq(i) then return
520 next i
530 i=-1
540 return
550 :
560 data "Lagos", 21.0
570 data "Cairo", 15.2
580 data "Kinshasa-Brazzaville", 11.3
590 data "Greater Johannesburg",  7.55
600 data "Mogadishu",  5.85
610 data "Khartoum-Omdurman",  4.98
620 data "Dar Es Salaam",  4.7
630 data "Alexandria",  4.58
640 data "Abidjan",  4.4
650 data "Casablanca",  3.98
660 data ""
Output:
ready.
run

Test 1. name='Dar Es Salaam':
  Index= 6 .

Test 2. population < 5M:
  Name=Khartoum-Omdurman.

Test 3. name like 'A%':
  Population=4.58.

ready.

FreeBASIC

Type Registro
    name As String*20
    population As Double
End Type
Dim cities(1 To 10) As Registro => { _
("Lagos",21.0 ), ("Cairo", 15.2 ), ("Kinshasa-Brazzaville", 11.3 ), _
("Greater Johannesburg", 7.55), ("Mogadishu", 5.85), ("Khartoum-Omdurman", 4.98), _
("Dar Es Salaam", 4.7 ), ("Alexandria", 4.58), ("Abidjan", 4.4 ), ("Casablanca", 3.98)}

Dim As Byte n
For n = 1 To Ubound(cities)
    If cities(n).name = "Dar Es Salaam" Then Print n-1
Next n

For n = 1 To Ubound(cities)
    If cities(n).population < 5.00 Then Print cities(n).name : Exit For
Next n

For n = 1 To Ubound(cities)
    If Left(cities(n).name,1) = "A" Then Print cities(n).population : Exit For
Next n
Sleep
Output:
 6
Khartoum-Omdurman
 4.58

QBasic

Works with: QBasic version 1.1
Works with: QuickBasic version 4.5
DIM cities$(10, 10)
cities$(1, 1) = "Lagos": cities$(1, 2) = "21.0"
cities$(2, 1) = "Cairo": cities$(2, 2) = "15.2"
cities$(3, 1) = "Kinshasa-Brazzaville": cities$(3, 2) = "11.3"
cities$(4, 1) = "Greater Johannesburg": cities$(4, 2) = "7.55"
cities$(5, 1) = "Mogadishu": cities$(5, 2) = "5.85"
cities$(6, 1) = "Khartoum-Omdurman": cities$(6, 2) = "4.98"
cities$(7, 1) = "Dar Es Salaam": cities$(7, 2) = "4.7"
cities$(8, 1) = "Alexandria": cities$(8, 2) = "4.58"
cities$(9, 1) = "Abidjan": cities$(9, 2) = "4.4"
cities$(10, 1) = "Casablanca": cities$(10, 2) = "3.98"

FOR n = 1 TO UBOUND(cities$)
    IF cities$(n, 1) = "Dar Es Salaam" THEN PRINT n - 1
NEXT n

FOR n = 1 TO UBOUND(cities$)
    IF VAL(cities$(n, 2)) < 5! THEN PRINT cities$(n, 1): EXIT FOR
NEXT n

FOR n = 1 TO UBOUND(cities$)
    IF LEFT$(cities$(n, 1), 1) = "A" THEN PRINT cities$(n, 2): EXIT FOR
NEXT n
Output:
Same as FreeBASIC entry.

True BASIC

DIM cities$(10, 10)
LET cities$(1, 1) = "Lagos"
LET cities$(1, 2) = "21.0"
LET cities$(2, 1) = "Cairo"
LET cities$(2, 2) = "15.2"
LET cities$(3, 1) = "Kinshasa-Brazzaville"
LET cities$(3, 2) = "11.3"
LET cities$(4, 1) = "Greater Johannesburg"
LET cities$(4, 2) = "7.55"
LET cities$(5, 1) = "Mogadishu"
LET cities$(5, 2) = "5.85"
LET cities$(6, 1) = "Khartoum-Omdurman"
LET cities$(6, 2) = "4.98"
LET cities$(7, 1) = "Dar Es Salaam"
LET cities$(7, 2) = "4.7"
LET cities$(8, 1) = "Alexandria"
LET cities$(8, 2) = "4.58"
LET cities$(9, 1) = "Abidjan"
LET cities$(9, 2) = "4.4"
LET cities$(10, 1) = "Casablanca"
LET cities$(10, 2) = "3.98"

FOR n = 1 TO UBOUND(cities$,1)
    IF cities$(n, 1) = "Dar Es Salaam" THEN PRINT n-1
NEXT n

FOR n = 1 TO UBOUND(cities$,1)
    IF VAL(cities$(n, 2)) < 5 THEN
       PRINT cities$(n, 1)
       EXIT FOR
    END IF
NEXT n

FOR n = 1 TO UBOUND(cities$,1)
    IF (cities$(n, 1))[1:1] = "A" THEN
       PRINT cities$(n, 2)
       EXIT FOR
    END IF
NEXT n
END
Output:
Same as FreeBASIC entry.

Yabasic

dim cities$(9, 9)
cities$(0, 0) = "Lagos"                : cities$(0, 1) = "21.0"
cities$(1, 0) = "Cairo"                : cities$(1, 1) = "15.2"
cities$(2, 0) = "Kinshasa-Brazzaville" : cities$(2, 1) = "11.3"
cities$(3, 0) = "Greater Johannesburg" : cities$(3, 1) = "7.55"
cities$(4, 0) = "Mogadishu"            : cities$(4, 1) = "5.85"
cities$(5, 0) = "Khartoum-Omdurman"    : cities$(5, 1) = "4.98"
cities$(6, 0) = "Dar Es Salaam"        : cities$(6, 1) = "4.7"
cities$(7, 0) = "Alexandria"           : cities$(7, 1) = "4.58"
cities$(8, 0) = "Abidjan"              : cities$(8, 1) = "4.4"
cities$(9, 0) = "Casablanca"           : cities$(9, 1) = "3.98"

for n = 1 to arraysize(cities$(), 1)
    if cities$(n, 0) = "Dar Es Salaam"  print n
next n

for n = 1 to arraysize(cities$(), 1)
    if val(cities$(n, 1)) < 5 then print cities$(n, 0): break: fi
next n

for n = 1 to arraysize(cities$(), 1)
    if left$(cities$(n, 0), 1) = "A" then print cities$(n, 1): break: fi
next n
Output:
Same as FreeBASIC entry.

C

This solution makes use of the 'bsearch' and 'lfind' library functions. Note: 'lfind' is available only on Posix systems, and is found in the 'search.h' header. However it is also part of the Ming C Compiler for Windows.

#include <stdint.h> /* intptr_t */
#include <stdio.h>
#include <stdlib.h> /* bsearch */
#include <string.h>
#include <search.h> /* lfind */
 
#define LEN(x) (sizeof(x) / sizeof(x[0]))
 
struct cd {
    char *name;
    double population;
};
 
/* Return -1 if name could not be found */
int search_get_index_by_name(const char *name, const struct cd *data, const size_t data_length,
        int (*cmp_func)(const void *, const void *))
{
    struct cd key = { (char *) name, 0 };
    struct cd *match = bsearch(&key, data, data_length,
            sizeof(struct cd), cmp_func);
 
    if (match == NULL)
        return -1;
    else
        return ((intptr_t) match - (intptr_t) data) / sizeof(struct cd);
}
 
/* Return -1 if no matching record can be found */
double search_get_pop_by_name(const char *name, const struct cd *data, size_t data_length,
        int (*cmp_func)(const void *, const void *))
{
    struct cd key = { (char *) name, 0 };
    struct cd *match = lfind(&key, data, &data_length,
            sizeof(struct cd), cmp_func);
 
    if (match == NULL)
        return -1;
    else
        return match->population;
}

/* Return NULL if no value satisfies threshold */
char* search_get_pop_threshold(double pop_threshold, const struct cd *data, size_t data_length,
        int (*cmp_func)(const void *, const void *))
{
    struct cd key = { NULL, pop_threshold };
    struct cd *match = lfind(&key, data, &data_length,
            sizeof(struct cd), cmp_func);
 
    if (match == NULL)
        return NULL;
    else
        return match->name;
}

int cd_nameChar_cmp(const void *a, const void *b)
{
    struct cd *aa = (struct cd *) a;
    struct cd *bb = (struct cd *) b;
	
	int i,len = strlen(aa->name);

	for(i=0;i<len;i++)
		if(bb->name[i]!=aa->name[i])
			return -1;
	return 0;
}
 
int cd_name_cmp(const void *a, const void *b)
{
    struct cd *aa = (struct cd *) a;
    struct cd *bb = (struct cd *) b;
    return strcmp(bb->name, aa->name);
}
 
int cd_pop_cmp(const void *a, const void *b)
{
    struct cd *aa = (struct cd *) a;
    struct cd *bb = (struct cd *) b;
    return bb->population >= aa->population;
}
 
int main(void)
{
    const struct cd citydata[] = {
        { "Lagos", 21 },
        { "Cairo", 15.2 },
        { "Kinshasa-Brazzaville", 11.3 },
        { "Greater Johannesburg", 7.55 },
        { "Mogadishu", 5.85 },
        { "Khartoum-Omdurman", 4.98 },
        { "Dar Es Salaam", 4.7 },
        { "Alexandria", 4.58 },
        { "Abidjan", 4.4 },
        { "Casablanca", 3.98 }
    };
 
    const size_t citydata_length = LEN(citydata);
 
    printf("%d\n", search_get_index_by_name("Dar Es Salaam", citydata, citydata_length, cd_name_cmp));
    printf("%s\n", search_get_pop_threshold(5, citydata, citydata_length, cd_pop_cmp));
    printf("%lf\n", search_get_pop_by_name("A", citydata, citydata_length, cd_nameChar_cmp));
    
    return 0;
}

Output

6
Khartoum-Omdurman
4.580000

C#

using System;
using System.Collections.Generic;

namespace RosettaSearchListofRecords
{
    class Program
    {
        static void Main(string[] args)
        {
            var dataset = new List<Dictionary<string, object>>() {
                new Dictionary<string, object>   {{ "name" , "Lagos"},                {"population", 21.0  }},
                new Dictionary<string, object>   {{ "name" , "Cairo"},                {"population", 15.2  }},
                new Dictionary<string, object>   {{ "name" , "Kinshasa-Brazzaville"}, {"population", 11.3  }},
                new Dictionary<string, object>   {{ "name" , "Greater Johannesburg"}, {"population",  7.55 }},
                new Dictionary<string, object>   {{ "name" , "Mogadishu"},            {"population",  5.85 }},
                new Dictionary<string, object>   {{ "name" , "Khartoum-Omdurman"},    {"population",  4.98 }},
                new Dictionary<string, object>   {{ "name" , "Dar Es Salaam"},        {"population",  4.7  }},
                new Dictionary<string, object>   {{ "name" , "Alexandria"},           {"population",  4.58 }},
                new Dictionary<string, object>   {{ "name" , "Abidjan"},              {"population",  4.4  }},
                new Dictionary<string, object>   {{ "name" , "Casablanca"},           {"population",  3.98 }}
            };

            // Find the (zero-based) index of the first city in the list whose name is "Dar Es Salaam"
            var index = dataset.FindIndex(x => ((string)x["name"]) == "Dar Es Salaam");
            Console.WriteLine(index);

            // Find the name of the first city in this list whose population is less than 5 million 
            var name = (string)dataset.Find(x => (double)x["population"] < 5.0)["name"];
            Console.WriteLine(name);

            // Find the population of the first city in this list whose name starts with the letter "A" 
            var aNamePopulation = (double)dataset.Find(x => ((string)x["name"]).StartsWith("A"))["population"];
            Console.WriteLine(aNamePopulation);
        }
    }
}
Output:
6
Khartoum-Omdurman
4.58

C++

std::find_if accepts a lambda as predicate.

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

struct city {
    std::string name;
    float population;
};

int main()
{
    std::vector<city> cities = {
        { "Lagos", 21 },
        { "Cairo", 15.2 },
        { "Kinshasa-Brazzaville", 11.3 },
        { "Greater Johannesburg", 7.55 },
        { "Mogadishu", 5.85 },
        { "Khartoum-Omdurman", 4.98 },
        { "Dar Es Salaam", 4.7 },
        { "Alexandria", 4.58 },
        { "Abidjan", 4.4 },
        { "Casablanca", 3.98 },
    };
    
    auto i1 = std::find_if( cities.begin(), cities.end(),
        [](city c){ return c.name == "Dar Es Salaam"; } );
    if (i1 != cities.end()) {
        std::cout << i1 - cities.begin() << "\n";
    }
    
    auto i2 = std::find_if( cities.begin(), cities.end(),
        [](city c){ return c.population < 5.0; } );
    if (i2 != cities.end()) {
        std::cout << i2->name << "\n";
    }
    
    auto i3 = std::find_if( cities.begin(), cities.end(),
        [](city c){ return c.name.length() > 0 && c.name[0] == 'A'; } );
    if (i3 != cities.end()) {
        std::cout << i3->population << "\n";
    }
}
Output:
6
Khartoum-Omdurman
4.58


Clojure

In order to not rely on the input ordering of the data records, this example adds an "idx" value to the records, for purposes of being able to report the answer to the queries which rely on the original ordering. The data records are then re-sorted to be ordered by city name. This helps to make it clear that the query relying on sort-by-population is properly handled in the query itself.

(def records [{:idx 8, :name "Abidjan",              :population  4.4}
              {:idx 7, :name "Alexandria",           :population  4.58}
              {:idx 1, :name "Cairo",                :population 15.2}
              {:idx 9, :name "Casablanca",           :population  3.98}
              {:idx 6, :name "Dar Es Salaam",        :population  4.7}
              {:idx 3, :name "Greater Johannesburg", :population  7.55}
              {:idx 5, :name "Khartoum-Omdurman",    :population  4.98}
              {:idx 2, :name "Kinshasa-Brazzaville", :population 11.3}
              {:idx 0, :name "Lagos",                :population 21.0}
              {:idx 4, :name "Mogadishu",            :population  5.85}])

(defn city->idx [recs city]
  (-> (some #(when (= city (:name %)) %)
            recs)
      :idx))

(defn rec-with-max-population-below-n [recs limit]
  (->> (sort-by :population > recs)
       (drop-while (fn [r] (>= (:population r) limit)))
       first))

(defn most-populous-city-below-n [recs limit]
  (:name (rec-with-max-population-below-n recs limit)))
Output:
(city->idx records "Dar Es Salaam")       ; 6

(most-populous-city-below-n records 5.0)  ; "Khartoum-Omdurman"

(->> (sort-by :idx records)
     (drop-while #(not (clojure.string/starts-with? (:name %) "A")))
     first
     :population)                         ; 4.58

Common Lisp

(defstruct city
  (name nil :type string)
  (population nil :type number))

(defparameter *cities*
  (list (make-city :name "Lagos"                :population 21.0)
        (make-city :name "Cairo"                :population 15.2)
        (make-city :name "Kinshasa-Brazzaville" :population 11.3)
        (make-city :name "Greater Johannesburg" :population  7.55)
        (make-city :name "Mogadishu"            :population  5.85)
        (make-city :name "Khartoum-Omdurman"    :population  4.98)
        (make-city :name "Dar Es Salaam"        :population  4.7)
        (make-city :name "Alexandria"           :population  4.58)
        (make-city :name "Abidjan"              :population  4.4)
        (make-city :name "Casablanca"           :population  3.98)))

(defun main ()
  (let ((answer1 (position "Dar Es Salaam" *cities* :key #'city-name :test #'string=))
        (answer2 (city-name (find-if (lambda (population) (< population 5))
                                     *cities* :key #'city-population)))
        (answer3 (city-population (find-if (lambda (name) (char= (char name 0) #\A))
                                           *cities* :key #'city-name))))
    (format t "Answer 1: ~A~%" answer1)
    (format t "Answer 2: ~A~%" answer2)
    (format t "Answer 3: ~A~%" answer3)))
Output:
Answer 1: 6
Answer 2: Khartoum-Omdurman
Answer 3: 4.58

EchoLisp

This example needs updating due to a modification in the task. Please examine and fix the code if needed, then remove this message.

Details:

  • You shouldn't parse the input from JSON - instead, show to readers what the data structure looks like natively.
  • A third test-case has been added.

We demonstrate the vector-search primitive, which takes as input a vector, and a predicate.

(require 'struct)
(require 'json)

;; importing data
(define cities
#<<
[{"name":"Lagos", "population":21}, {"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}]
>>#)

;; define a structure matching data
;; heterogenous  slots values
(struct city (name population))

;; convert JSON to EchoLisp instances of structures
(set! cities
	(vector-map (lambda(x) (json->struct x struct:city)) (json-import cities)))
	
;; search by name, case indifferent
(define (city-index name)
	(vector-search (lambda(x) (string-ci=? (city-name x) name)) cities))
	
;; returns first city name such as population < seuil
(define (city-pop seuil)
	(define idx (vector-search (lambda(x) (< (city-population x) seuil)) cities))
	(if idx
		(city-name (vector-ref cities idx))
		(cons seuil 'not-found)))


(city-index "Dar Es Salaam")  6
(city-pop 5)  "Khartoum-Omdurman"
(city-pop -666)  (-666 . not-found)
(city-index "alexandra")  #f

Elena

ELENA 6.x :

import extensions;
import system'routines;
 
public program()
{
    var dataset := new object[]
    {
        new { Name = "Lagos";  Population = 21.0r; },
        new { Name = "Cairo";  Population = 15.2r; },
        new { Name = "Kinshasa-Brazzaville";  Population = 11.3r; },
        new { Name = "Greater Johannesburg";  Population = 7.55r; },
        new { Name = "Mogadishu";  Population = 5.85r; },
        new { Name = "Khartoum-Omdurman";  Population = 4.98r; },
        new { Name = "Dar Es Salaam";  Population = 4.7r; },
        new { Name = "Alexandria";  Population = 4.58r; },
        new { Name = "Abidjan";  Population = 4.4r; },
        new { Name = "Casablanca";  Population = 3.98r; }
    };
 
    var index := dataset.selectBy::(r => r.Name).toArray().indexOfElement("Dar Es Salaam");
    console.printLine(index);
 
    var name := dataset.filterBy::(c => c.Population < 5.0r).toArray().FirstMember.Name;
    console.printLine(name);
 
    var namePopulation := dataset.filterBy::(c => c.Name.startingWith("A")).toArray().FirstMember.Population;
    console.printLine(namePopulation)
}
Output:
6
Khartoum-Omdurman
4.58

Elixir

cities = [
  [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]
]

IO.puts Enum.find_index(cities, fn city -> city[:name] == "Dar Es Salaam" end)
IO.puts Enum.find(cities, fn city -> city[:population] < 5.0 end)[:name]
IO.puts Enum.find(cities, fn city -> String.first(city[:name])=="A" end)[:population]
Output:
6
Khartoum-Omdurman
4.58

Factor

For our associative structure, we use the tuple: an object composed of named slots, each holding a value which can be accessed using automatically-generated accessors. Factor is built around combinators (Factor's word for higher-order functions), so completing the task as requested is idiomatic. find is an existing combinator that takes a sequence and a predicate quotation (quotation being Factor's word for anonymous function) and returns the first element of the sequence for which the predicate quotation yields t.

Not only does find return the element, but also the index, which allows us to use find for all of the required tasks. Since Factor is a stack-based concatenative language, multiple return values are elegant to use. We can simply drop the sequence element on the top of the data stack if we are only interested in the index, or we can nip the index if we are only interested in the sequence element on the top of the stack.

USING: accessors io kernel math prettyprint sequences ;
IN: rosetta-code.search-list

TUPLE: city name pop ;

CONSTANT: data {
    T{ city f "Lagos" 21.0 }
    T{ city f "Cairo" 15.2 }
    T{ city f "Kinshasa-Brazzaville" 11.3 }
    T{ city f "Greater Johannesburg" 7.55 }
    T{ city f "Mogadishu" 5.85 }
    T{ city f "Khartoum-Omdurman" 4.98 }
    T{ city f "Dar Es Salaam" 4.7 }
    T{ city f "Alexandria" 4.58 }
    T{ city f "Abidjan" 4.4 }
    T{ city f "Casablanca" 3.98 }
}

! Print the index of the first city named Dar Es Salaam.
data [ name>> "Dar Es Salaam" = ] find drop .

! Print the name of the first city with under 5 million people.
data [ pop>> 5 < ] find nip name>> print

! Print the population of the first city starting with 'A'.
data [ name>> first CHAR: A = ] find nip pop>> .
Output:
6
Khartoum-Omdurman
4.58

Fortran

In order to employ a compound data aggregate such as CITY with components CITY.NAME and CITY.POPULATION, F90 is required. Earlier, one would have employed a collection of separate arrays with similar names, such as CNAME and CPOP. This may still be desirable when array parameters from a data aggregate will be passed via copy-in and copy-out instead of by reference. An alternative declaration would be to have the components of the aggregate use the array aspect, as in REAL POPULATION(10) This would also avoid wasting storage due to multiple padding forced by any alignment requirements, as when a floating-point variable has to be aligned to a storage boundary. Otherwise, with "packed" storage, extra code required to access unaligned items consumes extra storage and of course, extra time. But the specification calls for multiplicity of the pairs. By contrast, pl/i offers "floating indexing" whereby CITY(i).NAME and CITY.NAME(i) would be acceptable usages for either form of declaration, thus concealing the issue.

As for the names, one must choose a maximum size for the city name, and 28 seems a perfect choice, even for names in Madagascar. Later fortran offers facilities for character variables "fitted to size", at the cost of extra indirection.

Fortran does not offer a "pass-by-name" facility, whereby the test function for the searches could be specified in the manner of Jensen's_Device, something like FINDFIRST(I,CITY(I).NAME .EQ. "Dar Es Salaam") and FINDFIRST(I,CITY(I).POPULATION < 5) in the form of boolean expressions evaluated in the calling environment, so one must devise a suitable procedure, and because the two components NAME and POPULATION have different types, the parameter matching protocol requires two different procedures. Via additional F90 syntax it is possible to define a "generic" routine with a single name that, when invoked, will in fact invoke the appropriate specific routine, however in this example one test is for equality, and the other is for "less than" so the commonality is weak. One could instead define two boolean functions (one each for the two types of test, say NAMEISEQUAL and POPULATIONISLESS) and pass the appropriate function as a parameter to a more general FINDFIRST routine, but this is both messy and restrictive: two functions to be defined separately and with FINDFIRST, all will only accept a type CITYSTAT as parameters. And as the TARGET parameter is of two different types, there can't be one FINDFIRST routine anyway.

Instead, two search functions. Using the function's name as a variable within the function could not be relied on prior to F90: some compilers would disallow it and in other cases odd results might be produced, so a local variable would have to be used. These functions turn out to be general in the sense that they're not limited to a type of CITYSTAT. Instead, FIRSTMATCH searches an array of texts, and FIRSTLESS an array of floating-point numbers - they could be applied to any such arrays. But sometimes at a cost. They are not prepared to deal with arrays having a "stride" other than one, such as the CITY.NAME entries, whose successive elements are not in successive storage locations. Instead, the compiler generates code to copy the desired elements from the CITY aggregate into a temporary variable having that arrangement, and passes that to the routine by reference. One could use the special declaration INTENT(IN) for read-only activities, and that will at least abate the copy-back, but for small items and only ten at that, this overhead can be ignored; otherwise in-line code would be required for each search. On the other hand, it does allow the special usage CITY.NAME(1:1) to search only the first character of each name.

Although F90 allows an array to be defined with a lower bound other than the default of one, this requires such a non-default lower bound to be specified in every declaration, which is tiresome, and leads to confusion over counting. Still, to suit the requirement, the index found for Dar Es Salaam is reduced by one. Returning a value of zero for "not found" is helpful (-1 would be good too, but this can't be an unsigned integer) and it is often useful to have an actual element zero with a dummy entry, such as CITYSTAT("--No such city!",3E33) so that a WRITE statement need not be prefaced by a test so as to avoid an index-out-of-bounds error. The dummy population value, if printed, will likely overflow its format code and fill its space with asterisks in the standard behaviour. More modern systems include the reading or writing of the special mnemonic "NaN" for "Not a Number" but this mnemonic is not recognised in fortran source itself so something like PARAMETER (NaN = Z'FFFFFFFFFFFFFFFF') would be needed if preferred - though readers may not recgnise that mnemonic either. With such a dummy-element scheme, the searches would be specified by FIRSTMATCH(CITY(1:).NAME,"Dar Es Salaam") to signify that the zero'th element was not involved. Alternatively, the special entry could follow the "live" entries and "not found" would be an index value of eleven, there being ten entries in this example. If entries are to be added or removed, this becomes tiresome, but it does mean that there need no longer be an assignment of the "not found" value after the DO-loop's search, because that will be the value of the index variable on exit - though some argue that no such exit value should be relied upon. Coherent organisation is required for this! Incidentally, 0 (zero) in the source continuation field is treated as a space (meaning no continuation), thus the letter o instead: O would be asking for misreading.

The specification mentions an ordered list: here, the items are indeed ordered in storage (as first, second, etc) but ordering more usefully refers to the values of the components. The example is presented in reducing order of population. More generally, the storage order might be arbitrary, and one would use indices, arrays such as XCNAME which would list the entries in the order of their names, and XCPOP their populations. These arrays would each be produced by an indexed sort process that would not move the data about, and so long as entries were not frequently altered (requiring re-sorting) these indices could be used for searching. IT = FIRSTMATCH(CITY(XCNAME).NAME,"Dar Es Salaam") would search the city names in alphabetical order rather than storage order and IT would be its position in XCNAME so that CITY(XCNAME(IT)).POPULATION would give the city's population. However, the "not found" result would be troublesome if not tested for. If zero was the value for that, arranging that XCNAME(0) was zero would help, however an often useful usage for XCNAME(0) is for it to contain the number of elements in its list.

Such arrays involve the ability to access an individual city's information at random, simply by specifying the index into the CITY array, however the given problem requires only sequential access. In such a case, the storage for the city elements could be formed as a linked-list which would be followed sequentially. Even so, random access can be regained via an array such as XCNAME, which now would hold the storage address of the corresponding CITY element. And as ever, how long is a piece of string? Here, ten.

If the data were stored as records in a disc file, a record zero won't exist and so appropriate testing for "not found" will be required. For this example however there is no attempt either to prepare a suitable "not found" entry nor to test and evade such a misfortune. The test data employed do not provoke such errors...

      MODULE SEMPERNOVIS	!Keep it together.
       TYPE CITYSTAT		!Define a compound data type.
        CHARACTER*28	NAME		!Long enough?
        REAL		POPULATION	!Accurate enough.
       END TYPE CITYSTAT	!Just two parts, but different types.
       TYPE(CITYSTAT) CITY(10)	!Righto, I'll have some.
       DATA CITY/		!Supply the example's data.
     1   CITYSTAT("Lagos",               21.0 ),
     2   CITYSTAT("Cairo",               15.2 ),
     3   CITYSTAT("Kinshasa-Brazzaville",11.3 ),
     4   CITYSTAT("Greater Johannesburg", 7.55),
     5   CITYSTAT("Mogadishu",            5.85),
     6   CITYSTAT("Khartoum-Omdurman",    4.98),
     7   CITYSTAT("Dar Es Salaam",        4.7 ),
     8   CITYSTAT("Alexandria",           4.58),
     9   CITYSTAT("Abidjan",              4.4 ),
     o   CITYSTAT("Casablanca",           3.98)/
       CONTAINS
        INTEGER FUNCTION FIRSTMATCH(TEXT,TARGET)	!First matching.
         CHARACTER*(*) TEXT(:)	!An array of texts.
         CHARACTER*(*) TARGET	!The text to look for.
          DO FIRSTMATCH = 1,UBOUND(TEXT,DIM = 1)	!Scan the array from the start.
            IF (TEXT(FIRSTMATCH) .EQ. TARGET) RETURN	!An exact match? Ignoring trailing spaces.
          END DO				!Try the next.
          FIRSTMATCH = 0		!No match. Oh dear.
        END FUNCTION FIRSTMATCH

        INTEGER FUNCTION FIRSTLESS(VAL,TARGET)	!First matching.
         REAL VAL(:)	!An array of values.
         REAL TARGET	!The value to look for.
          DO FIRSTLESS = 1,UBOUND(VAL,DIM = 1)	!Step through the array from the start.
            IF (VAL(FIRSTLESS) .LT. TARGET) RETURN	!Suitable?
          END DO				!Try the next.
          FIRSTLESS = 0		!No match. Oh dear.
        END FUNCTION FIRSTLESS
      END MODULE SEMPERNOVIS

      PROGRAM POKE
      USE SEMPERNOVIS	!Ex Africa, ...
      CHARACTER*(*) BLAH	!Save on some typing.
      PARAMETER (BLAH = "The first city in the list whose ")	!But also, for layout.

      WRITE (6,1) BLAH,FIRSTMATCH(CITY.NAME,"Dar Es Salaam") - 1	!My array starts with one.
    1 FORMAT (A,"name is Dar Es Salaam, counting with zero, is #",I0)

      WRITE (6,2) BLAH,CITY(FIRSTLESS(CITY.POPULATION,5.0)).NAME
    2 FORMAT (A,"population is less than 5 is ",A)

      WRITE (6,3) BLAH,CITY(FIRSTMATCH(CITY.NAME(1:1),"A")).POPULATION
    3 FORMAT (A,"whose name starts with A has population",F5.2)
      END

The words NAME and TARGET can have special usages in F90, but fortran has no reserved words so these names can be put to ordinary use. Alas, the syntax highlighter does not recognise their non-special use and gives them colour. One could fuss further over the layout of the output, but here it is:

The first city in the list whose name is Dar Es Salaam, counting with zero, is #6
The first city in the list whose population is less than 5 is Khartoum-Omdurman
The first city in the list whose whose name starts with 'A' has population 4.58

Go

Basic solution:

package main

import (
    "fmt"
    "strings"
)

type element struct {
    name       string
    population float64
}

var list = []element{
    {"Lagos", 21},
    {"Cairo", 15.2},
    {"Kinshasa-Brazzaville", 11.3},
    {"Greater Johannesburg", 7.55},
    {"Mogadishu", 5.85},
    {"Khartoum-Omdurman", 4.98},
    {"Dar Es Salaam", 4.7},
    {"Alexandria", 4.58},
    {"Abidjan", 4.4},
    {"Casablanca", 3.98},
}

func find(cond func(*element) bool) int {
    for i := range list {
        if cond(&list[i]) {
            return i
        }
    }
    return -1
}

func main() {
    fmt.Println(find(func(e *element) bool {
        return e.name == "Dar Es Salaam"
    }))

    i := find(func(e *element) bool {
        return e.population < 5
    })
    if i < 0 {
        fmt.Println("*** not found ***")
    } else {
        fmt.Println(list[i].name)
    }

    i = find(func(e *element) bool {
        return strings.HasPrefix(e.name, "A")
    })
    if i < 0 {
        fmt.Println("*** not found ***")
    } else {
        fmt.Println(list[i].population)
    }
}
Output:
6
Khartoum-Omdurman
4.58

Data conversion solution:

The prohibition on parsing JSON is unreasonable in any language. The alternative to parsing by computer is parsing manually, reformatting data with human fingers on a keyboard. It's okay for ten lines of test data but would be unreasonable in any real application. But let's say than in real life you have a pointy-haired boss that decrees that no JSON parsing will be done — even though he has contracted a vendor that supplies JSON only. You would write a data converter that quietly converts data outside the application.

First, a package to define the data structure needed. This package will be imported by both the data conversion tool and the application.

package datadef

type Element struct {
    Name       string
    Population float64
}

type List []Element

Then the data conversion tool. This program reads JSON from stdin and generates the Go code of a package "data" containing an equivalent Go literal.

package main

import (
    "encoding/json"
    "fmt"
    "go/build"
    "log"
    "os"
    "path/filepath"

    "datadef"
)

func main() {
    var l datadef.List
    if err := json.NewDecoder(os.Stdin).Decode(&l); err != nil {
        log.Fatal(err)
    }
    pp := filepath.Join(filepath.SplitList(build.Default.GOPATH)[0], "src/data")
    f, err := os.Create(filepath.Join(pp, "data.go"))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Fprintln(f, `package data
    
import "datadef"
    
var List = datadef.List {`)
    for i, e := range l {
        fmt.Fprintf(f, "   %d: {%q, %g},\n", i, e.Name, e.Population)
    }
    fmt.Fprintln(f, "}")
}
Output:
package data
    
import "datadef"
    
var List = datadef.List {
   0: {"Lagos", 21},
   1: {"Cairo", 15.2},
   2: {"Kinshasa-Brazzaville", 11.3},
   3: {"Greater Johannesburg", 7.55},
   4: {"Mogadishu", 5.85},
   5: {"Khartoum-Omdurman", 4.98},
   6: {"Dar Es Salaam", 4.7},
   7: {"Alexandria", 4.58},
   8: {"Abidjan", 4.4},
   9: {"Casablanca", 3.98},
}

The desired program imports the generated package containing the converted data. Program and imported data are JSON-free.

package main

import (
    "fmt"
    "strings"

    "data"
    "datadef"
)

func find(cond func(*datadef.Element) bool) int {
    for i := range data.List {
        if cond(&data.List[i]) {
            return i
        }
    }
    return -1
}

func main() {
    i := find(func(e *datadef.Element) bool {
        return e.Name == "Dar Es Salaam"
    })
    if i < 0 {
        fmt.Println("*** not found ***")
    } else {
        fmt.Println(i)
    }

    i = find(func(e *datadef.Element) bool {
        return e.Population < 5
    })
    if i < 0 {
        fmt.Println("*** not found ***")
    } else {
        fmt.Println(data.List[i].Name)
    }

    i = find(func(e *datadef.Element) bool {
        return strings.HasPrefix(e.Name, "A")
    })
    if i < 0 {
        fmt.Println("*** not found ***")
    } else {
        fmt.Println(data.List[i].Population)
    }
}

Output same as basic solution.

Solution using sorted population count:

The population ordering is useful only for queries against population and so cannot be used, at least not in any simple way, by the general find function shown above. The sort package of the Go standard library however contains a function for making general queries against an ordered list. This solution shows how the population query can be done with this function.

package main

import (
    "fmt"
    "sort"

    "data"
)

func main() {
    if !sort.SliceIsSorted(data.List, func(i, j int) bool {
        return data.List[i].Population > data.List[j].Population
    }) {
        panic("data not sorted by decreasing population")
    }

    i := sort.Search(len(data.List), func(i int) bool {
        return data.List[i].Population < 5
    })
    if i == len(data.List) {
        fmt.Println("*** not found ***")
    } else {
        fmt.Println(data.List[i].Name)
    }
}
Output:
Khartoum-Omdurman

sort.Search for the other queries:

The same sort.Search function is general enough to be used for the other two queries of the task as long as appropriate indexes are constructed. sort.Search is interesting because it is in the standard library and is much like the function required by the task, being generalized to take a function as an argument. It does not completely meet task requirements though because it works on a single ordering that must already exist or already be computed. A function that would analyze a general query, use available orderings when possible, and fall back on linear search otherwise is surely beyond the task scope.

package main

import (
    "fmt"
    "sort"
    "strings"

    "data"
)

func main() {
    nx := make([]int, len(data.List))
    for i := range nx {
        nx[i] = i
    }
    sort.Slice(nx, func(i, j int) bool {
        return data.List[nx[i]].Name < data.List[nx[j]].Name
    })

    i := sort.Search(len(nx), func(i int) bool {
        return data.List[nx[i]].Name >= "Dar Es Salaam"
    })
    if i == len(nx) || data.List[nx[i]].Name != "Dar Es Salaam" {
        fmt.Println("*** not found ***")
    } else {
        fmt.Println(nx[i])
    }

    for i := range nx {
        nx[i] = i
    }
    sort.SliceStable(nx, func(i, j int) bool {
        return data.List[nx[i]].Name[0] < data.List[nx[j]].Name[0]
    })

    i = sort.Search(len(nx), func(i int) bool {
        return data.List[nx[i]].Name >= "A"
    })
    if i == len(nx) || !strings.HasPrefix(data.List[nx[i]].Name, "A") {
        fmt.Println("*** not found ***")
    } else {
        fmt.Println(data.List[nx[i]].Population)
    }
}
Output:
6
4.58

Haskell

import Data.List (findIndex, find)

data City = City
  { name :: String
  , population :: Float
  } deriving (Read, Show)

-- CITY PROPERTIES ------------------------------------------------------------
cityName :: City -> String
cityName (City x _) = x

cityPop :: City -> Float
cityPop (City _ x) = x

mbCityName :: Maybe City -> Maybe String
mbCityName (Just x) = Just (cityName x)
mbCityName _ = Nothing

mbCityPop :: Maybe City -> Maybe Float
mbCityPop (Just x) = Just (cityPop x)
mbCityPop _ = Nothing

-- EXAMPLES -------------------------------------------------------------------
mets :: [City]
mets =
  [ City
    { name = "Lagos"
    , population = 21.0
    }
  , City
    { name = "Cairo"
    , population = 15.2
    }
  , City
    { name = "Kinshasa-Brazzaville"
    , population = 11.3
    }
  , City
    { name = "Greater Johannesburg"
    , population = 7.55
    }
  , City
    { name = "Mogadishu"
    , population = 5.85
    }
  , City
    { name = "Khartoum-Omdurman"
    , population = 4.98
    }
  , City
    { name = "Dar Es Salaam"
    , population = 4.7
    }
  , City
    { name = "Alexandria"
    , population = 4.58
    }
  , City
    { name = "Abidjan"
    , population = 4.4
    }
  , City
    { name = "Casablanca"
    , population = 3.98
    }
  ]

-- TEST -----------------------------------------------------------------------
main :: IO ()
main = do
  mbPrint $ findIndex (("Dar Es Salaam" ==) . cityName) mets
  mbPrint $ mbCityName $ find ((< 5.0) . cityPop) mets
  mbPrint $ mbCityPop $ find (("A" ==) . take 1 . cityName) mets

mbPrint
  :: Show a
  => Maybe a -> IO ()
mbPrint (Just x) = print x
mbPrint x = print x
Output:
6
"Khartoum-Omdurman"
4.58

J

To represent the data in the task description, we will be using a tabular format as follows:

colnumeric=: 0&".&.>@{`[`]}

data=: 1 colnumeric |: fixcsv 0 :0
Lagos, 21
Cairo, 15.2
Kinshasa-Brazzaville, 11.3
Greater Johannesburg, 7.55
Mogadishu, 5.85
Khartoum-Omdurman, 4.98
Dar Es Salaam, 4.7
Alexandria, 4.58
Abidjan, 4.4
Casablanca, 3.98
)

And here are the required computations:

   (0 { data) i. <'Dar Es Salaam'
6
   (i. >./)@(* 5&>)@:>@{: data
5
   5 {:: 0 {data
Khartoum-Omdurman
   (1 { data) {::~ 'A' i.~ {.&> 0 { data
4.58

The "general search function" mentioned in the task does not seem a natural fit for this set of data, because of the multi-column nature of this data. Nevertheless, we could for example define:

gsf=: 1 :0
:
   I. u x { y
)

This uses the single argument aspect of the definition of I. to convert a bit mask to the corresponding sequence of indices. And the column(s) we are searching on are exposed as a parameter for the interface, which allows us to ignore (for this problem) the irrelevant columns...

Thus, we could say:

   1 (= >./)@(* 5&>)@:> gsf data 
5

But this doesn't seem any clearer or more concise than our previous expression which finds the index of the first example of the most populous city with a population less than five million. Not only that, but if there were multiple cities which had the same population number which satisfied this constraint, this version would return all of those indices where the task explicitly required we return the first example.

J: Another approach

The following approach is arguably more natural in J than requiring a dictionary-type structure.

   city=: <;._1 ';Lagos;Cairo;Kinshasa-Brazzaville;Greater Johannesburg;Mogadishu;Khartoum-Omdurman;Dar Es Salaam;Alexandria;Abidjan;Casablanca'
   popln=: 21 15.2 11.3 7.55 5.85 4.98 4.7 4.58 4.4 3.98
   city i. <'Dar Es Salaam'              NB. index of Dar Es Salaam
6
   (city i. boxopen) 'Dar Es Salaam'     NB. anonymous search function with city name as argument
6
   city {::~ (popln < 5) {.@# \: popln   NB. name of first city with population less than 5 million
Khartoum-Omdurman
   popln&(city {::~ \:@[ {.@#~ <) 5      NB. anonymous search function with popln limit as argument
Khartoum-Omdurman
   popln {~ 'A' i.~ {.&> city            NB. population of first city whose name starts with "A"
4.58
   (popln {~ ({.&> city)&i.) 'A'         NB. anonymous search function with first letter as argument
4.58

Java

Java (up to and including) version 7 was not capable of using Predicates or the mentioned higher-order-Programming without external libraries. Java 8 introduced Predicated and Streams (not to be confused with the Java-IO-Streams!) that changed the way how collections of objects can be processed. This example illustrates the changes by solving the three subtasks in different ways:

  1. "find the index of the fist city [...]" uses a predicate, but the actual search is done using classic iteration (this is also because the streams don't maintain anything "index-like" and so this would not be possible using stream-processing).
  2. "find city name by population [...]" uses a predicate to descibe the "search term" and returns the name of the city
  3. "find the population by letter [...]" uses a predicate as search term and accepts a "consumer" so the caller of the method specifies what to do with the found result.
Works with: Java version 8
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * Represent a City and it's population.
 * City-Objects do have a natural ordering, they are ordered by their poulation (descending)
 */
class City implements Comparable<City> {
    private final String name;
    private final double population;

    City(String name, double population) {
        this.name = name;
        this.population = population;
    }

    public String getName() {
        return this.name;
    }

    public double getPopulation() {
        return this.population;
    }

    @Override
    public int compareTo(City o) {
        //compare for descending order. for ascending order, swap o and this
        return Double.compare(o.population, this.population);
    }
}

public class SearchListOfRecords {

    public static void main(String[] args) {

        //Array-of-City-Objects-Literal
        City[] datasetArray = {new City("Lagos", 21.),
                new City("Cairo", 15.2),
                new City("Kinshasa-Brazzaville", 11.3),
                new City("Greater Johannesburg", 7.55),
                new City("Mogadishu", 5.85),
                new City("Khartoum-Omdurman", 4.98),
                new City("Dar Es Salaam", 4.7),
                new City("Alexandria", 4.58),
                new City("Abidjan", 4.4),
                new City("Casablanca", 3.98)};

        //Since this is about "collections smarter that arrays", the Array is converted to a List
        List<City> dataset = Arrays.asList(datasetArray);

        //the City-Objects know that they are supposed to be compared by population
        Collections.sort(dataset);


        //Find the first City that matches the given predicate and print it's index in the dataset
        //the Predicate here is given in the form a Java 8 Lambda that returns true if the given name
        //Note that the Predicate is not limited to searching for names. It can operate on anything one can done with
        // and compared about City-Objects
        System.out.println(findIndexByPredicate(dataset, city -> city.getName().equals("Dar Es Salaam")));

        //Find the first City whose population matches the given Predicate (here: population <= 5.) and print it's name
        //here the value is returned an printed by the caller
        System.out.println(findFirstCityByPredicate(dataset, city -> city.getPopulation() <= 5.));

        //Find the first City that matches the given predicate (here: name starts with "A") and
        //apply the given consumer (here: print the city's population)
        //here the caller specifies what to do with the object. This is the most generic solution and could also be used to solve Task 2
        applyConsumerByPredicate(dataset, city -> city.getName().startsWith("A"), city -> System.out.println(city.getPopulation()));

    }

    /**
     * Finds a City by Predicate.
     * The predicate can be anything that can be done or compared about a City-Object.
     * <p>
     * Since the task was to "find the index" it is not possible to use Java 8's stream facilities to solve this.
     * The Predicate is used very explicitly here - this is unusual.
     *
     * @param dataset the data to operate on, assumed to be sorted
     * @param p       the Predicate that wraps the search term.
     * @return the index of the City in the dataset
     */
    public static int findIndexByPredicate(List<City> dataset, Predicate<City> p) {
        for (int i = 0; i < dataset.size(); i++) {
            if (p.test(dataset.get(i)))
                return i;
        }
        return -1;
    }

    /**
     * Finds and returns the name of the first City where the population matches the Population-Predicate.
     * This solutions makes use of Java 8's stream facilities.
     *
     * @param dataset   the data to operate on, assumed to be sorted
     * @param predicate a predicate that specifies the city searched. Can be "any predicate that can be applied to a City"
     * @return the name of the first City in the dataset whose population matches the predicate
     */
    private static String findFirstCityByPredicate(List<City> dataset, Predicate<City> predicate) {
        //turn the List into a Java 8 stream, so it can used in stream-operations
        //filter() by the specified predicate (to the right of this operation, only elements matching the predicate are left in the stream)
        //find the first element (which is "the first city..." from the task)
        //get() the actualy object (this is necessary because it is wrapped in a Java 8 Optional<T>
        //getName() the name and return it.
        return dataset.stream().filter(predicate).findFirst().get().getName();
    }

    /**
     * In specified dataset, find the first City whose name matches the specified predicate, and apply the specified consumer
     * <p>
     * Since this can be solved pretty much like the "find a city by population", this has been varied. The caller specifies what to do with the result.
     * So this method does not return anything, but requiers a "consumer" that processes the result.
     *
     * @param dataset      the data to operate on, assumed to be sorted
     * @param predicate    a predicate that specifies the city searched. Can be "any predicate that can be applied to a City"
     * @param doWithResult a Consumer that specified what to do with the results
     */
    private static void applyConsumerByPredicate(List<City> dataset, Predicate<City> predicate, Consumer<City> doWithResult) {
        //turn the List in to a Java 8 stream in stream-operations
        //filter() by the specified predicate (to the right of this operation, only elements matching the predicate are left in the stream)
        //find the first element (which is "the first city..." from the task)
        // if there is an element found, feed it to the Consumer
        dataset.stream().filter(predicate).findFirst().ifPresent(doWithResult);
    }
}
Output:
6
Khartoum-Omdurman
4.58

JavaScript

ES5

(function () {
    'use strict';
 
    // find :: (a -> Bool) -> [a] -> Maybe a
    function find(f, xs) {
        for (var i = 0, lng = xs.length; i < lng; i++) {
            if (f(xs[i])) return xs[i];
        }
        return undefined;
    }
 
    // findIndex :: (a -> Bool) -> [a] -> Maybe Int
    function findIndex(f, xs) {
        for (var i = 0, lng = xs.length; i < lng; i++) {
            if (f(xs[i])) return i;
        }   
        return undefined;
    }
 
 
    var lst = [
      { "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 }
    ];
 
    return {
        darEsSalaamIndex: findIndex(function (x) {
            return x.name === 'Dar Es Salaam';
        }, lst),
 
        firstBelow5M: find(function (x) {
                return x.population < 5;
            }, lst)
            .name,
 
        firstApop: find(function (x) {
                return x.name.charAt(0) === 'A';
            }, lst)
            .population
    };
 
})();


Output:
{"darEsSalaamIndex":6, "firstBelow5M":"Khartoum-Omdurman", "firstApop":4.58}

ES6

(() => {
    'use strict';
 
    let lst = [
          { "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 }
        ];
 
    return {
        darEsSalaamIndex: lst.findIndex(x => x.name === 'Dar Es Salaam'),
        firstBelow5M: lst.find(x => x.population < 5)
            .name,
        firstApop: lst.find(x => x.name[0] === 'A')
            .population
    };
 
})();


Output:
{"darEsSalaamIndex":6, "firstBelow5M":"Khartoum-Omdurman", "firstApop":4.58}

jq

"jq" is so-name because it is a JSON Query Language, and thus all the abstractions are already available for the given searches, except that early versions of jq do not have `first/1` as a builtin. If your jq does not define `first/1`, then for present purposes, an appropriate definition would be:

def first(s): [s][0];

This will emit `null` if the stream, s, is empty.

In each case where `first/1` is used below, a less efficient alternative is also shown.

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

   map(.name) | index("Dar Es Salaam")

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

   first(.[] | select(.population < 5)) | .name
   # Alternatively:
   map(select(.population < 5)) | .[0] | .name

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

   first(.[] | select(.name[0:1] == "A")) | .population
   # Alternatively:
   map(select(.name[0:1] == "A")) | .[0] | .population

Julia

Works with: Julia version 0.6
using DataFrames

dataset = DataFrame(name=["Lagos", "Cairo", "Kinshasa-Brazzaville", "Greater Johannesburg", "Mogadishu",
                          "Khartoum-Omdurman", "Dar Es Salaam", "Alexandria", "Abidjan", "Casablanca"],
                    population=[21.0, 15.2, 11.3, 7.55, 5.85, 4.98, 4.7, 4.58, 4.4, 3.98])

print("Find the (one-based) index of the first city in the list whose name is \"Dar Es Salaam\": ")
println(findfirst(dataset[:name], "Dar Es Salaam"))
print("Find the name of the first city in this list whose population is less than 5 million: ")
println(dataset[first(find(dataset[:population] .< 5)), :name])
print("Find the population of the first city in this list whose name starts with the letter \"A\": ")
println(dataset[first(find(startswith.(dataset[:name], 'A'))), :population])
Output:
Find the (one-based) index of the first city in the list whose name is "Dar Es Salaam": 7
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

Kotlin

// version 1.1.2

class City(val name: String, val pop: Double)

val cities = listOf(
    City("Lagos", 21.0),
    City("Cairo", 15.2),
    City("Kinshasa-Brazzaville", 11.3),
    City("Greater Johannesburg", 7.55),
    City("Mogadishu", 5.85),
    City("Khartoum-Omdurman", 4.98),
    City("Dar Es Salaam", 4.7),
    City("Alexandria", 4.58),
    City("Abidjan", 4.4),
    City("Casablanca", 3.98)
)

fun main(args: Array<String>) {
    val index = cities.indexOfFirst { it.name == "Dar Es Salaam" }
    println("Index of first city whose name is 'Dar Es Salaam'          = $index")
    val name = cities.first { it.pop < 5.0 }.name
    println("Name of first city whose population is less than 5 million = $name")
    val pop = cities.first { it.name[0] == 'A' }.pop
    println("Population of first city whose name starts with 'A'        = $pop")
}
Output:
Index of first city whose name is 'Dar Es Salaam'          = 6
Name of first city whose population is less than 5 million = Khartoum-Omdurman
Population of first city whose name starts with 'A'        = 4.58

Lingo

on findFirstRecord (data, condition)
  cnt = data.count
  repeat with i = 1 to cnt
    record = data[i]
    if value(condition) then return [#index:i-1, #record:record]
  end repeat
end
data = [\
  [ "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 ]\
]
  
q = QUOTE

-- Find the (zero-based) index of the first city in the list whose name is "Dar Es Salaam"
res = findFirstRecord(data, "record.name="&q&"Dar Es Salaam"&q)
if listP(res) then put res.index
-- 6

-- Find the name of the first city in this list whose population is less than 5 million
res = findFirstRecord(data, "record.population<5")
if listP(res) then put res.record.name
-- "Khartoum-Omdurman"

-- Find the population of the first city in this list whose name starts with the letter "A"
res = findFirstRecord(data, "record.name.char[1]="&q&"A"&q)
if listP(res) then put res.record.population
-- 4.5800

Lua

Lua tables are well suited as the element type for this task. The master data structure is a table of tables.

-- Dataset declaration
local cityPops = {
    {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}
}

-- Function to search a dataset using a custom match function
function recordSearch (dataset, matchFunction)
    local returnValue
    for index, element in pairs(dataset) do
        returnValue = matchFunction(index, element)
        if returnValue then return returnValue end
    end
    return nil
end

-- Main procedure
local testCases = {
    function (i, e) if e.name == "Dar Es Salaam" then return i - 1 end end,
    function (i, e) if e.population < 5 then return e.name end end,
    function (i, e) if e.name:sub(1, 1) == "A" then return e.population end end
}
for _, func in pairs(testCases) do print(recordSearch(cityPops, func)) end
Output:
6
Khartoum-Omdurman
4.58

Ksh

#!/bin/ksh 

# Search a list of records

#	# Variables:
#
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 }'

typeset -a African_Metro
integer i=0

typeset -T Metro_Africa_t=(
	typeset -h		'Metro name'		met_name=''
	typeset -E3 -h	'Metro population'	met_pop

	function init_metro {
		typeset name ; name="$1"
		typeset pop ; typeset -E3 pop=$2

		_.met_name=${name}
		_.met_pop=${pop}
	}

	function prt_name {
		print "${_.met_name}"
	}

	function prt_pop {
		print "${_.met_pop}"
	}
)

#	# Functions:
#

#	# Function _findcityindex(arr, name) - return array index of citry named "name"
#
function _findcityindex {
	typeset _arr ; nameref _arr="$1"
	typeset _name ; _name="$2"
	typeset _i ; integer _i

	for ((_i=0; _i<${#_arr[*]}; _i++)); do
		[[ ${_name} == $(_arr[_i].prt_name) ]] && echo ${_i} && return 0
	done
	
	echo "-1"
	return 1
}

#	# Function _findcitynamepop(arr, pop, xx) - find 1st city name pop $3 of $2
#
function _findcitynamepop {
	typeset _arr ; nameref _arr="$1"
	typeset _pop ; typeset -E3 _pop=$2
	typeset _comp ; _comp="$3"
	typeset _i ; integer _i

	for ((_i=0; _i<${#_arr[*]}; _i++)); do
		case ${_comp} in
		gt)
			[[ $(_arr[_i].prt_pop) -gt ${_pop} ]] && _arr[_i].prt_name && return 0 ;;
		lt)
			[[ $(_arr[_i].prt_pop) -lt ${_pop} ]] && _arr[_i].prt_name && return 0 ;;
		esac
	done
	
	echo "DNE"
	return 1
}

#	# Function _findcitypopname(arr, pat) - find pop of first city starting w/ pat
#
function _findcitypopname {
	typeset _arr ; nameref _arr="$1"
	typeset _pat ; _pat="$2"
	typeset _i ; integer _i

	for ((_i=0; _i<${#_arr[*]}; _i++)); do
		[[ $(_arr[_i].prt_name) == ${_pat}* ]] && _arr[_i].prt_pop && return 0
	done
	
	echo "-1"
	return 1
}

 ######
# main #
 ######

#	# An indexed array of Type variable (objects)
#
echo "${json}" | while read; do
	metro="${REPLY#*\"name\"\:\ }" ; metro="${metro%%\,*}" ;  metro="${metro//\"/}"
	population="${REPLY#*\"population\"\:\ }" ; population=${population%+(\ )\}*(\,)}

	Metro_Africa_t African_Metro[i]
	African_Metro[i++].init_metro "${metro}" ${population}
done

_findcityindex African_Metro "Dar Es Salaam"
_findcitynamepop African_Metro 5.0 lt
_findcitypopname African_Metro "A"
Output:

6 Khartoum-Omdurman

4.58

Maple

rec := [table(["name"="Lagos","population"=21.0]),
      table(["name"="Cairo","population"=15.2]),
      table(["name"="Kinshasa-Brazzaville","population"=11.3]),
      table(["name"="Greater Johannesburg","population"=7.55]),
      table(["name"="Mogadishu","population"=5.85]),
      table(["name"="Khartoum-Omdurman","population"=4.98]),
      table(["name"="Dar Es Salaam","population"=4.7  ]),
      table(["name"="Alexandria","population"=4.58]),
      table(["name"="Abidjan","population"=4.4]),
      table(["name"="Casablanca","population"=3.98])]:

searchRec := proc(rec, pred, operation)
	local i:
	for i to numelems(rec) do
		if pred(rec[i]) then
			return operation(rec[i],i):
		fi:
	od:
end proc:	
searchRec(rec, x->x["name"] = "Dar Es Salaam", (x,i)->print(i-1)): # minus 1 since Maple is 1-indexed
searchRec(rec, x->x["population"]<5, (x,i)->print(x["name"])):
searchRec(rec, x->x["name"][1] = "A", (x,i)->print(x["population"])):
Output:
                               6
                      "Khartoum-Omdurman"
                              4.58

Mathematica/Wolfram Language

data = Dataset[{
  <|"name" -> "Lagos", "population" -> 21.|>, 
  <|"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|>
}]
data[Position["Dar Es Salaam"], "name"][1, 1] - 1
data[Select[#population < 5 &]][1, "name"]
data[Select[StringMatchQ[#name, "A*"] &]][1, "population"]

Nim

To solve this task, we define a template “findIt” similar to the templates provided by the standard library module “sequtils”. As First argument it accepts any collection providing a “pairs” iterator (yielding an index and a value), for instance a sequence (list) or a table (hash). The second argument of the template is a predicate, i.e. an expression containing the “it” variable.

This way, the template is able to work in a lot of contexts.

template findIt(data, pred: untyped): int =
  ## Return the index of the first element in "data" satisfying
  ## the predicate "pred" or -1 if no such element is found.
  var result = -1
  for i, it {.inject.} in data.pairs:
    if pred:
      result = i
      break
  result


when isMainModule:

  import strutils

  type City = tuple[name: string; population: float]

  const Cities: seq[City] = @[("Lagos", 21.0),
                              ("Cairo", 15.2),
                              ("Kinshasa-Brazzaville", 11.3),
                              ("Greater Johannesburg", 7.55),
                              ("Mogadishu", 5.85),
                              ("Khartoum-Omdurman", 4.98),
                              ("Dar Es Salaam", 4.7),
                              ("Alexandria", 4.58),
                              ("Abidjan", 4.4),
                              ("Casablanca", 3.98)]

  echo "Index of the first city whose name is “Dar Es Salaam”: ",
      Cities.findIt(it.name == "Dar Es Salaam")

  let idx1 = Cities.findIt(it.population < 5)
  echo "Name of the first city whose population is less than 5 million: ",
      if idx1 == -1: "<none>" else: Cities[idx1].name

  let idx2 = Cities.findIt(it.name.startsWith("A"))
  echo "Population of the first city whose name starts with the letter “A”: ",
      if idx2 == -1: "<none>" else: $Cities[idx2].population
Output:
Index of the first city whose name is “Dar Es Salaam”: 6
Name of the first city whose population is less than 5 million: Khartoum-Omdurman
Population of the first city whose name starts with the letter “A”: 4.58

OCaml

Works with: OCaml version 4.03+
#load "str.cma"


(* We are going to use literally a list of records as said in the title of the
 * task. *)
(* First: Definition of the record type. *)
type city = {
  name : string;
  population : float
} 

(* Second: The actual list of records containing the data. *)
let cities = [
  { 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 }
]


(* I can't find in the standard library any function in module List that returns
 * an index. Well, never mind, I make my own... *)
let find_index pred =
  let rec doloop i = function
    | [] -> raise Not_found
    | x :: xs -> if pred x then i else doloop (i + 1) xs
  in
  doloop 0


(* List.find returns the first element that satisfies the predicate.
 * List.filter or List.find_all would return *all* the elements that satisfy the
 * predicate. *)
let get_first pred = List.find pred


(* Simulate the 'startswith' function found in other languages. *)
let startswith sub s =
  Str.string_match (Str.regexp sub) s 0


let () =
  (* We use a typical dot notation to access the record fields. *)
  find_index (fun c -> c.name = "Dar Es Salaam") cities
  |> print_int
  |> print_newline;

  (get_first (fun c -> c.population < 5.0) cities).name
  |> print_endline;

  (get_first (fun c -> startswith "A" c.name) cities).population
  |> print_float
  |> print_newline;
Output:
6
Khartoum-Omdurman
4.58

Pascal

Free Pascal

program Search_list_records;
{$mode ObjFPC}{$H+}

type
  TCity = record
    name: string;
    population: real;
  end;

const
  Cities: array of TCity = (
    (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)
  );

function FindCityIndex(const CityName: string): Integer;
var
  i: Integer;
begin
  Result := -1; 
  for i := 0 to High(Cities) do
    if Cities[i].name = CityName then
      Exit(i);
end;

function FindCityName(const pop: real): string;
var
  City: TCity;
begin
  Result := 'not found'; 
  for City in Cities do
    if City.population < pop then
      Exit(City.name);
end;

function FindCityPopulation(const Start: Char): Real;
var
  City: TCity;
begin
  Result := -1; 
  for City in Cities do
    if City.name[1] = Start then
      Exit(City.population);
end;

begin
  writeln('index: ', FindCityIndex('Dar Es Salaam'));
  writeln('name: ', FindCityName(5.0));
  writeln('population: ', FindCityPopulation('A'):4:2);
end.
Output:
index: 6
name: Khartoum-Omdurman
population: 4.58

Perl

The first function from the core module List::Util provides short-circuiting search using a block as predicate. However, it can only return the value of the found element, not its index – so for the first test-case we need to operate on the list of indices.

use feature 'say';
use List::Util qw(first);

my @cities = (
  { 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 },
);

my $index1 = first { $cities[$_]{name} eq 'Dar Es Salaam' } 0..$#cities;
say $index1;

my $record2 = first { $_->{population} < 5 } @cities;
say $record2->{name};

my $record3 = first { $_->{name} =~ /^A/ } @cities;
say $record3->{population};
Output:
6
Khartoum-Omdurman
4.58

The CPAN module List::MoreUtils provides the first_index function which could be used to write that first case more elegantly:

use List::MoreUtils qw(first_index);

$index1 = first_index { $_->{name} eq 'Dar Es Salaam' } @cities;

Phix

Library: Phix/basics
constant CITY_NAME = 1, POPULATION = 2
constant municipalities = {{"Lagos",21},
                           {"Cairo",15.2},
                           {"Kinshasa-Brazzaville",11.3},
                           {"Greater Johannesburg",7.55},
                           {"Mogadishu",5.85},
                           {"Khartoum-Omdurman",4.98},
                           {"Dar Es Salaam",4.7},
                           {"Alexandria",4.58},
                           {"Abidjan",4.4},
                           {"Casablanca",3.98}}
 
function searchfor(sequence s, integer rid, object user_data, bool return_index=false)
    for i=1 to length(s) do
        if rid(s[i],user_data) then
            return iff(return_index?i:s[i])
        end if
    end for
    return 0 -- not found
end function
 
function city_named(sequence si, string city_name)
    return si[CITY_NAME]==city_name
end function
 
?searchfor(municipalities,city_named,"Dar Es Salaam",true)
 
function smaller_than(sequence si, atom population)
    return si[POPULATION]<population
end function
 
?searchfor(municipalities,smaller_than,5)[CITY_NAME]
 
function starts_with(sequence si, integer ch)
    return si[CITY_NAME][1]=ch
end function
 
?searchfor(municipalities,starts_with,'A')[POPULATION]

The columnize function reorganises hetrogenous data into corresponding homogenous arrays, which can make this sort of thing much simpler, at least for exact matches.

constant {cities,populations} = columnize(municipalities)

?populations[find("Dar Es Salaam",cities)]
Output:
7
"Khartoum-Omdurman"
4.58
4.7

Note that Phix subscripts are 1-based, hence the output of 7 not 6.

Phixmonti

include ..\Utilitys.pmt

(
  ( "Lagos"                21.0  )
  ( "Cairo"                15.2  )
  ( "Kinshasa-Brazzaville" 11.3  )
  ( "Greater Johannesburg"  7.55 )
  ( "Mogadishu"             5.85 )
  ( "Khartoum-Omdurman"     4.98 )
  ( "Dar Es Salaam"         4.7  )
  ( "Alexandria"            4.58 )
  ( "Abidjan"               4.4  )
  ( "Casablanca"            3.98 )
)

len for >ps
	( tps 1 ) sget "Dar Es Salaam" == if ps> 1 - ? exitfor else cps endif
endfor

len for
	get 2 get 5 < if 1 get ? drop exitfor else drop endif
endfor

len for >ps
	( tps 1 1 ) sget 'A' == if ( ps> 2 ) sget ? exitfor else cps endif
endfor
Output:
6
Khartoum-Omdurman
4.58

=== Press any key to exit ===

PHP

<?php

$data_array = [
  ['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],
]; 
$found=0;
$search_name = 'Dar Es Salaam';
echo "Find the (zero-based) index of the first city in the list whose name is \"$search_name\" - 6";

$index = array_search($search_name, array_column($data_array, 'name'));
$population = $data_array[$index]['population'];
echo "\nAnswer 1: Index: [$index] Population for $search_name is $population Million\n";
 
$search_val = 5;
echo "\nFind the name of the first city in this list whose population is less than $search_val million - Khartoum-Omdurman";
foreach ($data_array as $index => $row) {
  if ($row['population'] < $search_val) {
    $name = $row['name'];
    echo "\nAnswer 2: Index [$index] Population for $row[name] is $row[population] Million\n";
    break;
  }
}
 
$search_term = 'A';
echo "\n\nFind the population of the first city in this list whose name starts with the letter \"$search_term\" - 4.58";
foreach ($data_array as $index => $row) {
  if (strpos($row['name'], $search_term) === 0) {
    echo "\nAnswer 3: Index: [$index] Population for $row[name] is $row[population] Million\n";
    break;
  }
}
 
echo "\nDone...";

Output:
Find the (zero-based) index of the first city in the list whose name is "Dar Es Salaam" - 6
Answer 1: Index: [6] Population for Dar Es Salaam is 4.7 Million

Find the name of the first city in this list whose population is less than 5 million - Khartoum-Omdurman
Answer 2: Index [5] Population for Khartoum-Omdurman is 4.98 Million

Find the population of the first city in this list whose name starts with the letter "A" - 4.58
Answer 3: Index: [7] Population for Alexandria is 4.58 Million

Done...

PicoLisp

(scl 2)

(de *Data
   ("Lagos"                21.0)
   ("Cairo"                15.2)
   ("Kinshasa-Brazzaville" 11.3)
   ("Greater Johannesburg" 7.55)
   ("Mogadishu"            5.85)
   ("Khartoum-Omdurman"    4.98)
   ("Dar Es Salaam"        4.7)
   ("Alexandria"           4.58)
   ("Abidjan"              4.4)
   ("Casablanca"           3.98) )

(test 6
   (dec (index (assoc "Dar Es Salaam" *Data) *Data)) )

(test "Khartoum-Omdurman"
   (car (find '((L) (> 5.0 (cadr L))) *Data)) )

(test 4.58
   (cadr (find '((L) (pre? "A" (car L))) *Data)) )

PowerShell

The ConvertFrom-Json cmdlet converts a JSON formatted string to a custom PSCustomObject object that has a property for each field in the JSON string:

$jsonData = @'
[
    { "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 }
]
'@

$cities = $jsonData | ConvertFrom-JSON

The $cities variable contains an array of objects with Name and Population properties:

$cities
Output:
Name                 Population
----                 ----------
Lagos                      21.0
Cairo                      15.2
Kinshasa-Brazzaville       11.3
Greater Johannesburg       7.55
Mogadishu                  5.85
Khartoum-Omdurman          4.98
Dar Es Salaam               4.7
Alexandria                 4.58
Abidjan                     4.4
Casablanca                 3.98

Find the index of the first city in the list whose name is "Dar Es Salaam":

$cities.Name.IndexOf("Dar Es Salaam")
Output:
6

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

($cities | Where-Object -Property Population -LT 5)[0].Name
Output:
Khartoum-Omdurman

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

($cities | Where-Object -Property Name -Match "^A")[0].Population
Output:
4.58

Python

cities = [
    { "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 }
]

def first(query):
    return next(query, None)

print(
    first(index for index, city in enumerate(cities)
        if city['name'] == "Dar Es Salaam"),
    first(city['name'] for city in cities if city['population'] < 5),
    first(city['population'] for city in cities if city['name'][0] == 'A'),
    sep='\n')
Output:
6
Khartoum-Omdurman
4.58

Racket

The more idiomatic functions for the task is findf but it doesn't provide the position of the element in the list, so we write a variant. If the item is not found we return #f as most of the Racket primitives do in these cases.

#lang racket

(define (findf/pos proc lst)
  (let loop ([lst lst] [pos 0])
    (cond
      [(null? lst) #f]
      [(proc (car lst)) pos]
      [else (loop (cdr lst) (add1 pos))])))

Now we define the list that has the data for the task.

(define data '(#hash((name . "Lagos") (population . 21))
               #hash((name . "Cairo") (population .  15.2))
               #hash((name . "Kinshasa-Brazzaville") (population .  11.3))
               #hash((name . "Greater Johannesburg") (population .  7.55))
               #hash((name . "Mogadishu") (population .  5.85))
               #hash((name . "Khartoum-Omdurman") (population .  4.98))
               #hash((name . "Dar Es Salaam") (population .  4.7))
               #hash((name . "Alexandria") (population .  4.58))
               #hash((name . "Abidjan") (population .  4.4))
               #hash((name . "Casablanca") (population .  3.98))))

We write tiny wrappers to retrieve values from the hash.

(define get-name
  (lambda (x) (hash-ref x 'name)))

(define get-population
  (lambda (x) (hash-ref x 'population)))

For completeness, ensure the data is sorted by population largest to smallest.

(define sorted-data (sort data > #:key get-population))

Use an unnamed function with our findf/pos function to get the position of "Dar Es Salaam".

(findf/pos (lambda (x) (equal? "Dar Es Salaam" (get-name x))) sorted-data)
;; -> 6

Use unnamed functions with findf for the other two test cases.

(get-name (findf (lambda (x) (< (get-population x) 5)) sorted-data))
;; -> "Khartoum-Omdurman"
(get-population (findf (lambda (x) (regexp-match? #rx"^A" (get-name x))) sorted-data))
;; -> 4.58
Output:
6
"Khartoum-Omdurman"
4.58

Raku

(formerly Perl 6)

The built-in method .first fulfills the requirements of this task.
It takes any smart-matcher as a predicate. The :k adverb makes it return the key (i.e. numerical index) instead of the value of the element.

Works with: Rakudo version 2016.08
my @cities =
  { 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 },
;

say @cities.first(*<name> eq 'Dar Es Salaam', :k);
say @cities.first(*<population> < 5).<name>;
say @cities.first(*<name>.match: /^A/).<population>;
Output:
6
Khartoum-Omdurman
4.58

REXX

It is more idiomatic in REXX to use sparse arrays to express a list of CSV values, especially those which have
embedded blanks in them   (or other special characters).

Most REXX interpreters use (very efficient) hashing to index sparse arrays, which is much faster than performing an
incremental (sequential) search through an indexed array.

Only one loop is needed to find the result for the 2nd task requirement   (although the loop could be eliminated).
The other two task requirements are found without using traditional   IF   statements.

The approach taken in this REXX program makes use of a   DO WHILE   and   DO UNTIL   structure which
makes it much simpler (and idiomatic) and easier to code   (instead of adding multiple   IF   statements to a
generic search routine/function).

This REXX version does   not   rely on the list being sorted by population count.

/*REXX program (when using criteria) locates values (indices)  from an associate array. */
$="Lagos=21,  Cairo=15.2,  Kinshasa-Brazzaville=11.3, Greater Johannesburg=7.55, Mogadishu=5.85,",
  "Khartoum-Omdurman=4.98, Dar Es Salaam=4.7,  Alexandria=4.58,   Abidjan=4.4,  Casablanca=3.98"
@.= '(city not found)';    city.= "(no city)"       /*city search results for not found.*/
                                                    /* [↓]  construct associate arrays. */
    do #=0  while $\='';  parse var $ c '=' p "," $;  c=space(c);  parse var c a 2;  @.c=#
    city.#=c;  pop.#=p;  pop.c=#;  if @.a==@.  then @.a=c;  /*assign city, pop, indices.*/
    end   /*#*/                                     /* [↑]  city array starts at 0 index*/
                        /*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ task 1:  show the  INDEX  of a city.*/
town= 'Dar Es Salaam'                               /*the name of a city for the search.*/
say 'The city of ' town " has an index of: " @.town /*show (zero─based) index of a city.*/
say                     /*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ task 2:  show 1st city whose pop<5 M*/
many=5                                              /*size of a city's pop in millions. */
      do k=0  for #  until pop.k<many; end          /*find a city's pop from an index.  */
say '1st city that has a population less than '     many     " million is: "    city.k
say                     /*▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ task 3:  show 1st city with A* name.*/
c1= 'A'                                             /*1st character of a city for search*/
say '1st city that starts with the letter' c1 "is: " @.c1 /*stick a fork in it, all done*/

output   when using the default inputs:

The city of  Dar Es Salaam  has an index of:  6

1st city that has a population less than  5  million is:  Khartoum-Omdurman

1st city that starts with the letter A is:  Alexandria

Ring

# Project : Search a list of records

cities = [[: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]]

for n = 1 to len(cities)
     if cities[n][:name] = "Dar Es Salaam"
        see n-1 + nl
     ok
next

for n = 1 to len(cities)
     if cities[n][:population] < 5.00
        see cities[n][:name] + nl
        exit
     ok
next

for n = 1 to len(cities)
     if left(cities[n][:name],1) = "A"
        see cities[n][:population] + nl
        exit
     ok
next

Output:

6
Khartoum-Omdurman
4.58

Ruby

cities = [
    {name: "Lagos", population: 21}, 
    {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},
]

puts cities.index{|city| city[:name] == "Dar Es Salaam"}      # => 6
puts cities.find {|city| city[:population] < 5.0}[:name]      # => Khartoum-Omdurman
puts cities.find {|city| city[:name][0] == "A"}[:population]  # => 4.58

Rust

struct City {
    name: &'static str,
    population: f64,
}

fn main() {
    let cities = [
        City {
            name: "Lagos",
            population: 21.0,
        },
        City {
            name: "Cairo",
            population: 15.2,
        },
        City {
            name: "Kinshasa-Brazzaville",
            population: 11.3,
        },
        City {
            name: "Greater Johannesburg",
            population: 7.55,
        },
        City {
            name: "Mogadishu",
            population: 5.85,
        },
        City {
            name: "Khartoum-Omdurman",
            population: 4.98,
        },
        City {
            name: "Dar Es Salaam",
            population: 4.7,
        },
        City {
            name: "Alexandria",
            population: 4.58,
        },
        City {
            name: "Abidjan",
            population: 4.4,
        },
        City {
            name: "Casablanca",
            population: 3.98,
        },
    ];

    println!(
        "{:?}",
        cities.iter().position(|city| city.name == "Dar Es Salaam")
    );
    println!(
        "{:?}",
        cities
            .iter()
            .find(|city| city.population < 5.0)
            .map(|city| city.name)
    );
    println!(
        "{:?}",
        cities
            .iter()
            .find(|city| city.name.starts_with('A'))
            .map(|city| city.population)
    );
}
Output:
Some(6)
Some("Khartoum-Omdurman")
Some(4.58)

Scala

Output:

See it in running in your browser by ScalaFiddle (JavaScript executed in browser) or by Scastie (remote JVM).

object SearchListOfRecords extends App {
  val cities = Vector(
    City("Lagos", 21.0e6),
    City("Cairo", 15.2e6),
    City("Kinshasa-Brazzaville", 11.3e6),
    City("Greater Johannesburg", 7.55e6),
    City("Mogadishu", 5.85e6),
    City("Khartoum-Omdurman", 4.98e6),
    City("Dar Es Salaam", 4.7e6),
    City("Alexandria", 4.58e6),
    City("Abidjan", 4.4e6),
    City("Casablanca", 3.98e6)
  )

  def index = cities.indexWhere((_: City).name == "Dar Es Salaam")

  def name = cities.find(_.pop < 5.0e6).map(_.name)

  def pop = cities.find(_.name(0) == 'A').map(_.pop)

  case class City(name: String, pop: Double)

  println(
    s"Index of first city whose name is 'Dar Es Salaam'          = $index\n" +
      s"Name of first city whose population is less than 5 million = ${name.get}\n" +
      f"Population of first city whose name starts with 'A'        = ${pop.get}%,.0f")

}
Output:
Index of first city whose name is 'Dar Es Salaam'          = 6
Name of first city whose population is less than 5 million = Khartoum-Omdurman
Population of first city whose name starts with 'A'        = 4,580,000

Scheme

Library: Scheme/SRFIs

High-level functions for finding items in lists are provided by the (srfi 1) library:

  • (find pred? list) returns the first item matching the given pred? function, or #f if none match
  • (list-index pred? list) is similar but returns the index of the match (or #f)

The predicate can be used to pick out the part of a compound structure we want to find.

In a similar way (srfi 132) provides sorting routines with user-defined predicates: one is illustrated to ensure the list of items is sorted in decreasing population order.

(import (scheme base)
        (scheme char)
        (scheme write)
        (srfi 1)    ; lists
        (srfi 132)) ; sorting

(define-record-type <places> ; compound data type is a record with two fields
                    (make-place name population)
                    place?
                    (name place-name)
                    (population place-population))

(define *items* 
  (list-sort ; sort by decreasing population
    (lambda (r1 r2) (> (place-population r1)
                       (place-population r2)))
    (list (make-place "Lagos" 21.0)
          (make-place "Cairo" 15.2)
          (make-place "Kinshasa-Brazzaville" 11.3)
          (make-place "Greater Johannesburg" 7.55)
          (make-place "Mogadishu" 5.85)
          (make-place "Khartoum-Omdurman" 4.98)
          (make-place "Dar Es Salaam" 4.7)
          (make-place "Alexandria" 4.58)
          (make-place "Abidjan" 4.4)
          (make-place "Casablanca" 3.98))))

;; Find the (zero-based) index of the first city in the list
;; whose name is "Dar Es Salaam"
(display "Test 1: ")
(display (list-index (lambda (item) 
                       (string=? "Dar Es Salaam" (place-name item)))
                     *items*))
(newline)

;; Find the name of the first city in this list 
;; whose population is less than 5 million
(display "Test 2: ")
(display (place-name 
           (find (lambda (item) 
                   (< (place-population item) 5.0))
                 *items*)))
(newline)

;; Find the population of the first city in this list 
;; whose name starts with the letter "A" 
(display "Test 3: ")
(display (place-population 
           (find (lambda (item) 
                   (char=? (string-ref (place-name item) 0)
                           #\A))
                 *items*)))
(newline)
Output:
Test 1: 6
Test 2: Khartoum-Omdurman
Test 3: 4.58

Sidef

struct City {
    String name,
    Number population,
}

var cities = [
    City("Lagos", 21),
    City("Cairo", 15.2),
    City("Kinshasa-Brazzaville", 11.3),
    City("Greater Johannesburg", 7.55),
    City("Mogadishu", 5.85),
    City("Khartoum-Omdurman", 4.98),
    City("Dar Es Salaam", 4.7),
    City("Alexandria", 4.58),
    City("Abidjan", 4.4),
    City("Casablanca", 3.98),
]

say cities.index{|city| city.name == "Dar Es Salaam"}
say cities.first{|city| city.population < 5.0}.name
say cities.first{|city| city.name.begins_with("A")}.population
Output:
6
Khartoum-Omdurman
4.58

SQL

I probably wrote the C implementation for this problem. It has been quite some time, anyways, I got a notification that this page has been edited and while browsing it on my phone I found that this most database worthy of problems doesn't have a SQL implementation. Thus even after a long day, I logged back in again, to rosettacode, not work.

I am kind of fond of SQL, I am not a DBA but wanted to be one when I started my career. Databases are among the few things I still hold in respect :)

Credits : This wouldn't have been possible without https://sqliteonline.com , you can create your own tables and run queries on them without installing your own DB. The queries below should work on most DBs but some like Access ( is that really a DB ? ) doesn't have LIMIT, or so I read.

But to get started, first we create the table :

PS : I realised after posting this implementation that not all cities in this list are capitals, well, it was a long day :P

create table african_capitals(name varchar2(100), population_in_millions number(3,2));

Then we load the data :

insert into african_capitals values("Lagos", 21.0);
insert into african_capitals values("Cairo",15.2);
insert into african_capitals values("Kinshasa-Brazzaville",11.3);
insert into african_capitals values("Greater Johannesburg",7.55);
insert into african_capitals values("Mogadishu",5.85);
insert into african_capitals values("Khartoum-Omdurman",4.98);
insert into african_capitals values("Dar Es Salaam",4.7);
insert into african_capitals values("Alexandria",4.58);
insert into african_capitals values("Abidjan",4.4);
insert into african_capitals values("Casablanca",3.98);

If you are using sqliteonline.com, run the select query below to inspect your data :

select * from african_capitals;

Now we are ready to fire the queries to solve the problem statements, one note though : DB tables are 1 indexed, hence the capital of Tanzania is the 7th item, not 6th as is the case for C and it's vast family.

with temp as(select name,row_number() over() as rownum from african_capitals) select rownum from temp where name="Dar Es Salaam";
Output:
7

The LIMIT keyword in the 2nd and 3rd queries is not supported by all DBs, it works on Oracle and SQLite though

select name from african_capitals where population_in_millions < 5 limit 1;
Output:
Khartoum-Omdurman
select population_in_millions from african_capitals where name like "A%" limit 1;
Output:
4.58

Standard ML

type city = { name : string, population : real }

val citys : city list = [
        { 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 } ]

val firstCityi   = #1 (valOf (List.findi (fn (_, city) => #name(city) = "Dar Es Salaam") citys))
val firstBelow5M = #name (valOf (List.find (fn city => #population(city) < 5.0) citys))
val firstPopA    = #population (valOf (List.find (fn city => String.substring (#name(city), 0, 1) = "A") citys))
Output:
val firstCityi = 6 : int
val firstBelow5M = "Khartoum-Omdurman" : string
val firstPopA = 4.58 : real

Swift

Data:

struct Place {
  var name: String
  var population: Double
}

let places = [
  Place(name: "Lagos", population: 21.0),
  Place(name: "Cairo", population: 15.2),
  Place(name: "Kinshasa-Brazzaville", population: 11.3),
  Place(name: "Greater Johannesburg", population: 7.55),
  Place(name: "Mogadishu", population: 5.85),
  Place(name: "Khartoum-Omdurman", population: 4.98),
  Place(name: "Dar Es Salaam", population: 4.7),
  Place(name: "Alexandria", population: 4.58),
  Place(name: "Abidjan", population: 4.4),
  Place(name: "Casablanca", population: 3.98)
]

Using built-in methods

guard let salaamI = places.firstIndex(where: { $0.name == "Dar Es Salaam" }) else {
  fatalError()
}

print("Dar Es Salaam has index: \(salaamI)")

guard let lessThan5 = places.first(where: { $0.population < 5 }) else {
  fatalError()
}

print("First city with less than 5mil population: \(lessThan5.name)")

guard let startsWithA = places.first(where: { $0.name.hasPrefix("A") }) else {
  fatalError()
}

print("Population of first city starting with A: \(startsWithA.population)")
Output:
Dar Es Salaam has index: 6
First city with less than 5mil population: Khartoum-Omdurman
Population of first city starting with A: 4.58

Custom method using Key Paths

extension Collection {
  func firstIndex<V: Equatable>(
    withProperty prop: KeyPath<Element, V>,
    _ op: (V, V) -> Bool,
    _ val: V
  ) -> Index? {
    for i in indices where op(self[i][keyPath: prop], val) {
      return i
    }

    return nil
  }
}

guard let salaamI = places.firstIndex(withProperty: \.name, ==, "Dar Es Salaam") else {
  fatalError()
}

print("Dar Es Salaam has index: \(salaamI)")

guard let lessThan5I = places.firstIndex(withProperty: \.population, <, 5) else {
  fatalError()
}

print("First city with less than 5mil population: \(places[lessThan5I].name)")

guard let aI = places.firstIndex(withProperty: \.name, { $0.hasPrefix($1) }, "A") else {
  fatalError()
}

print("Population of first city starting with A: \(places[aI].population)")
Output:

Same as first method

Tcl

# records is a list of dicts.
set records {
  { 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 }
}

# Tcl's version of "higher order programming" is a bit unusual.  Instead of passing lambda
# functions, it is often easier to pass script fragments.  This command takes two such
# arguments: $test is an expression (as understood by [expr]), and $action is a script.
# thanks to [dict with], both $test and $action can refer to the fields of the current
# record by name - or to other variables used in the proc, like $index or $record.
proc search {records test action} {
    set index 0
    foreach record $records {
        dict with record {}
        if $test $action
        incr index
    }
    error "No match found!"
}

#  Find the (zero-based) index of the first city in the list whose name is "Dar Es Salaam"
puts [search $records {$name eq "Dar Es Salaam"} {return $index}]
#  Find the name of the first city in this list whose population is less than 5 million
puts [search $records {$population < 5.0} {return $name}]
#  Find the population of the first city in this list whose name starts with the letter "A"
puts [search $records {[string match A* $name]} {return $population}]
Output:
6
Khartoum-Omdurman
4.58

V (Vlang)

const cities = {"Lagos": 21.0, "Cairo": 15.2, "Kinshasa-Brazzaville": 11.3, "Greater Johannesburg": 7.55, "Mogadishu": 5.85, "Khartoum-Omdurman": 4.98, "Dar Es Salaam": 4.7, "Alexandria": 4.58, "Abidjan": 4.4, "Casablanca": 3.98}	

fn main() {
	mut count := 0
	mut result :=""
	for city, population in cities {
		count++
		if city == "Dar Es Salaam" {
			if !result.contains("Index") {result += "Index of '${city}': ${count - 1}\n"}
		}
		if population < 5 {
			if !result.contains("million") {result += "First city with less than 5 million: ${city}\n"}
		}
		if city[0].ascii_str() == "A" {
			if !result.contains("letter") {result += "First population that starts with letter 'A': ${population}\n"}
		}
	}
	println(result.all_before_last("\n"))
}
Output:
First city with less than 5 million: Khartoum-Omdurman 
Index of 'Dar Es Salaam': 6 
First population that starts with letter 'A': 4.58

Wren

Library: Wren-dynamic
import "./dynamic" for Tuple

var Element = Tuple.create("Element", ["record", "index"])

var findFirst = Fn.new { |seq, pred|
    var i = 0
    for (e in seq) {
        if (pred.call(e)) return Element.new(e, i)
        i = i + 1
    }
    return Element.new(null, -1)
}

var City = Tuple.create("City", ["name", "pop"])

var cities = [
    City.new("Lagos", 21.0),
    City.new("Cairo", 15.2),
    City.new("Kinshasa-Brazzaville", 11.3),
    City.new("Greater Johannesburg", 7.55),
    City.new("Mogadishu", 5.85),
    City.new("Khartoum-Omdurman", 4.98),
    City.new("Dar Es Salaam", 4.7),
    City.new("Alexandria", 4.58),
    City.new("Abidjan", 4.4),
    City.new("Casablanca", 3.98)
]

var index = findFirst.call(cities) { |c| c.name == "Dar Es Salaam" }.index
System.print("Index of the first city whose name is 'Dar Es Salaam' is %(index).")
var city = findFirst.call(cities) { |c| c.pop < 5 }.record.name
System.print("First city whose population is less than 5 million is %(city).")
var pop = findFirst.call(cities) { |c| c.name[0] == "A" }.record.pop
System.print("The population of the first city whose name begins with 'A' is %(pop).")
Output:
Index of the first city whose name is 'Dar Es Salaam' is 6.
First city whose population is less than 5 million is Khartoum-Omdurman.
The population of the first city whose name begins with 'A' is 4.58.

zkl

list:=T(SD("name","Lagos", 		  "population",21.0), // SD is a fixed dictionary
        SD("name","Cairo", 		  "population",15.2), 
	SD("name","Kinshasa-Brazzaville", "population",11.3), 
	SD("name","Greater Johannesburg", "population", 7.55), 
	SD("name","Mogadishu", 		  "population", 5.85), 
	SD("name","Khartoum-Omdurman", 	  "population", 4.98), 
	SD("name","Dar Es Salaam", 	  "population", 4.7), 
	SD("name","Alexandria", 	  "population", 4.58), 
	SD("name","Abidjan", 		  "population", 4.4), 
	SD("name","Casablanca", 	  "population", 3.98));

// Test case 1:
n:=list.filter1n(fcn(city){ city["name"]=="Dar Es Salaam" });  // one way
n:=list.filter1n(fcn(city){ city["name"].matches("dar es salaam") }); // or this way
n.println("==index of ",list[n].values);

// Test case 2:
city:=list.filter1(fcn(city){ city["population"]<5.0 });  // stop after first match
city["name"].println(" is the first city with population under 5 million.");

// Test case 3:
city:=list.filter1(fcn(city){ city["name"][0]=="A" });
println("The first \"A*\" city (%s) with population under 5 million: %f".fmt(city.values.xplode()));

where a SD is a small read only dictionary and filter1 is a filter that stops at the first match (returning the matched item). The filter method returns False on failure. The YAJL library could be used to parse the JSON data directly (eg if the data is from the web).

Output:
6==index of L("Dar Es Salaam",4.7)
Khartoum-Omdurman is the first city with population under 5 million.
The first "A*" city (Alexandria) with population under 5 million: 4.580000