Odd words

From Rosetta Code
Odd words is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Given a list of words   (using the words from the dictionary:   unixdict.txt).

Take odd indices letters from the word,   and if it's in the list,   then display the   odd word   on this page.

The length of the   odd word   should be   >   4.


Other tasks related to string operations:
Metrics
Counting
Remove/replace
Anagrams/Derangements/shuffling
Find/Search/Determine
Formatting
Song lyrics/poems/Mad Libs/phrases
Tokenize
Sequences



Ada

Using instances of generic procedure to filter odd/even words. <lang Ada>with Ada.Text_Io; with Ada.Containers.Indefinite_Ordered_Maps;

procedure Odd_Words is

  use Ada.Text_Io;
  package String_Maps is
    new Ada.Containers.Indefinite_Ordered_Maps (Key_Type     => String,
                                                Element_Type => String);
  Filename : constant String := "unixdict.txt";
  Words    : String_Maps.Map;
  function Get_Odd (Word : String) return String is
     Odd : String (1 .. (Word'Length + 1) / 2);
  begin
     for Index in Odd'Range loop
        Odd (Index) := Word (1 + 2 * (Index - 1));
     end loop;
     return Odd;
  end Get_Odd;
  function Get_Even (Word : String) return String is
     Even : String (1 .. Word'Length / 2);
  begin
     for Index in Even'Range loop
        Even (Index) := Word (1 + 1 + 2 * (Index - 1));
     end loop;
     return Even;
  end Get_Even;
  generic
     with function Filter (Word : String) return String;
  procedure Iterate_Map;
  procedure Iterate_Map is
  begin
     for Word of Words loop
        declare
           Half : constant String := Filter (Word);
        begin
           if Half'Length > 4 and then Words.Contains (Half) then
              Put (Word); Set_Col (15); Put_Line (Half);
           end if;
        end;
     end loop;
  end Iterate_Map;
  procedure Put_Odd_Words  is new Iterate_Map (Get_Odd);
  procedure Put_Even_Words is new Iterate_Map (Get_Even);
  File : File_Type;

begin

  Open (File, In_File, Filename);
  while not End_Of_File (File) loop
     declare
        Word : constant String := Get_Line (File);
     begin
        Words.Insert (Word, Word);
     end;
  end loop;
  Close (File);
  Put_Line ("Odd words:");
  Put_Odd_Words;
  New_Line;
  Put_Line ("Even words:");
  Put_Even_Words;

end Odd_Words;</lang>

Output:
Odd words:
barbarian     brain
childbear     cider
corrigenda    cried
gargantuan    grata
headdress     hades
palladian     plain
propionate    point
salvation     slain
siltation     slain
slingshot     sight
statuette     saute
supersede     spree
supervene     spree
terminable    trial

Even words:
cannonball    annal
importation   motto
psychopomp    scoop
starvation    train
upholstery    posey

ALGOL 68

Works with: ALGOL 68G version Any - tested with release 2.8.3.win32

Based on (and almost identical to) the Alternade Words sample. <lang algol68># find words where the odd letters also form a word #

  1. use the associative array in the Associate array/iteration task #

PR read "aArray.a68" PR IF FILE input file;

   STRING file name = "unixdict.txt";
   open( input file, file name, stand in channel ) /= 0

THEN

   # failed to open the file                                        #
   print( ( "Unable to open """ + file name + """", newline ) )

ELSE

   # file opened OK                                                 #
   BOOL at eof := FALSE;
   # set the EOF handler for the file #
   on logical file end( input file, ( REF FILE f )BOOL:
                                    BEGIN
                                        # note that we reached EOF on the #
                                        # latest read #
                                        at eof := TRUE;
                                        # return TRUE so processing can continue #
                                        TRUE
                                    END
                      );
   # returns w split into n parts by taking alternate characters    #
   PRIO SPLIT = 1;
   OP   SPLIT = ( STRING w, INT n )[]STRING:
        BEGIN
           [ n ]STRING result;
           FOR r pos FROM LWB result TO UPB result DO result[ r pos ] := "" OD;
           INT r pos := 1;
           FOR w pos FROM LWB w TO UPB w DO
               result[ r pos ] +:= w[ w pos ];
               r pos +:= 1;
               IF r pos > n THEN r pos := 1 FI
           OD;
           result
        END; # SPLIT #
   # build an associative array of the words                        #
   REF AARRAY words := INIT LOC AARRAY;
   WHILE STRING word;
         get( input file, ( word, newline ) );
         NOT at eof
   DO
       words // word := word
   OD;
   close( input file );
   # find the words where the odd letters form a word at least five #
   # characters long, the word itself must therefore be at least    #
   # nine characters long                                           #
   REF AAELEMENT e := FIRST words;
   WHILE e ISNT nil element DO
       IF STRING word = key OF e;
          INT w len = ( UPB word + 1 ) - LWB word;
          w len >= 9
       THEN
           []STRING sub word = word SPLIT 2;
           IF words CONTAINSKEY sub word[ 1 ]
           THEN
               print( ( word, ": " ) );
               FROM w len + 1 TO 18 DO print( ( " " ) ) OD;
               print( ( sub word[ 1 ], newline ) )
           FI
       FI;
       e := NEXT words
   OD

FI</lang>

Output:

As with the Alternade Words Algol 68 sample, the output is not sorted, it has been sorted here for ease of comparison with the other samples' output.

barbarian:          brain
childbear:          cider
corrigenda:         cried
gargantuan:         grata
headdress:          hades
palladian:          plain
propionate:         point
salvation:          slain
siltation:          slain
slingshot:          sight
statuette:          saute
supersede:          spree
supervene:          spree
terminable:         trial

Arturo

<lang rebol>words: read.lines relative "unixdict.txt"

getOdd: function [w][

   odd: new ""
   loop.with:'i w 'ch [
       if even? i -> 'odd ++ ch
   ]
   odd

]

loop words 'word [

   ow: getOdd word
   if and? [4 < size ow][contains? words ow] ->
       print [word "=>" ow]

]</lang>

Output:
barbarian => brain 
childbear => cider 
corrigenda => cried 
gargantuan => grata 
headdress => hades 
palladian => plain 
propionate => point 
salvation => slain 
siltation => slain 
slingshot => sight 
statuette => saute 
supersede => spree 
supervene => spree 
terminable => trial

AWK

<lang AWK>

  1. syntax: GAWK -f ODD_WORDS.AWK unixdict.txt
  2. sorting:
  3. PROCINFO["sorted_in"] is used by GAWK
  4. SORTTYPE is used by Thompson Automation's TAWK

{ arr[$0]++ } END {

   PROCINFO["sorted_in"] = "@ind_str_asc" ; SORTTYPE = 1
   main("13579","odd")
   main("02468","even")
   exit(0)

} function main(pattern,text, i,tmp,word) {

   pattern = sprintf("[%s]$",pattern)
   printf("\n%s:\n",text)
   for (word in arr) {
     tmp = ""
     for (i=1; i<=length(word); i++) {
       if (i ~ pattern) {
         tmp = tmp substr(word,i,1)
       }
     }
     if (length(tmp) > 4 && tmp in arr) {
       printf("%-11s %s\n",word,tmp)
     }
   }

} </lang>

Output:
odd:
barbarian   brain
childbear   cider
corrigenda  cried
gargantuan  grata
headdress   hades
palladian   plain
propionate  point
salvation   slain
siltation   slain
slingshot   sight
statuette   saute
supersede   spree
supervene   spree
terminable  trial

even:
cannonball  annal
importation motto
psychopomp  scoop
starvation  train
upholstery  posey

C++

<lang cpp>#include <cstdlib>

  1. include <fstream>
  2. include <iomanip>
  3. include <iostream>
  4. include <set>
  5. include <string>
  6. include <utility>
  7. include <vector>

using word_list = std::vector<std::pair<std::string, std::string>>;

void print_words(std::ostream& out, const word_list& words) {

   int n = 1;
   for (const auto& pair : words) {
       out << std::right << std::setw(2) << n++ << ": "
           << std::left << std::setw(14) << pair.first
           << pair.second << '\n';
   }

}

int main(int argc, char** argv) {

   const char* filename(argc < 2 ? "unixdict.txt" : argv[1]);
   std::ifstream in(filename);
   if (!in) {
       std::cerr << "Cannot open file '" << filename << "'.\n";
       return EXIT_FAILURE;
   }
   const int min_length = 5;
   std::string line;
   std::set<std::string> dictionary;
   while (getline(in, line)) {
       if (line.size() >= min_length)
           dictionary.insert(line);
   }
   word_list odd_words, even_words;
   for (const std::string& word : dictionary) {
       if (word.size() < min_length + 2*(min_length/2))
           continue;
       std::string odd_word, even_word;
       for (auto w = word.begin(); w != word.end(); ++w) {
           odd_word += *w;
           if (++w == word.end())
               break;
           even_word += *w;
       }
       if (dictionary.find(odd_word) != dictionary.end())
           odd_words.emplace_back(word, odd_word);
       if (dictionary.find(even_word) != dictionary.end())
           even_words.emplace_back(word, even_word);
   }
   std::cout << "Odd words:\n";
   print_words(std::cout, odd_words);
   std::cout << "\nEven words:\n";
   print_words(std::cout, even_words);
   return EXIT_SUCCESS;

}</lang>

Output:
Odd words:
 1: barbarian     brain
 2: childbear     cider
 3: corrigenda    cried
 4: gargantuan    grata
 5: headdress     hades
 6: palladian     plain
 7: propionate    point
 8: salvation     slain
 9: siltation     slain
10: slingshot     sight
11: statuette     saute
12: supersede     spree
13: supervene     spree
14: terminable    trial

Even words:
 1: cannonball    annal
 2: importation   motto
 3: psychopomp    scoop
 4: starvation    train
 5: upholstery    posey

=F#

<lang fsharp> // Odd words: Nigel Galloway. June 9th., 2021 let dict=seq{use n=System.IO.File.OpenText("unixdict.txt") in while not n.EndOfStream do yield n.ReadLine()}|>Seq.filter(fun n->n.Length>4)|>List.ofSeq let fN g=let n=g|>String.mapi(fun n g->if n%2=0 then g else ' ')|>String.filter((<>)' ') in match List.contains n dict with true->Some(n,g) |_->None dict|>Seq.filter(fun n->n.Length>6)|>Seq.choose fN|>Seq.iter(fun(n,g)->printfn "%s -> %s" g n) </lang>

Output:
barbarian -> brain
childbear -> cider
corrigenda -> cried
gargantuan -> grata
headdress -> hades
palladian -> plain
propionate -> point
salvation -> slain
siltation -> slain
slingshot -> sight
statuette -> saute
supersede -> spree
supervene -> spree
terminable -> trial

Factor

This is basically the same program as https://rosettacode.org/wiki/Alternade_words#Factor. <evens> is a virtual sequence representing the (zero-based) even indices of the input sequence, which this task calls the odd indices.

Works with: Factor version 0.99 2020-08-14

<lang factor>USING: formatting hash-sets io io.encodings.ascii io.files kernel literals math sequences sequences.extras sets strings ;

<< CONSTANT: words $[ "unixdict.txt" ascii file-lines ] >>

CONSTANT: wordset $[ words >hash-set ]

odd ( str -- newstr ) <evens> >string ;

"Odd words > 4:" print words [ length 8 > ] filter [ odd wordset in? ] filter [ dup odd "%-15s %s\n" printf ] each</lang>

Output:
Odd words > 4:
barbarian       brain
childbear       cider
corrigenda      cried
gargantuan      grata
headdress       hades
palladian       plain
propionate      point
salvation       slain
siltation       slain
slingshot       sight
statuette       saute
supersede       spree
supervene       spree
terminable      trial

FreeBASIC

<lang freebasic>#define NULL 0

type node

   word as string*32   'enough space to store any word in the dictionary
   nxt as node ptr

end type

function addword( tail as node ptr, word as string ) as node ptr

   'allocates memory for a new node, links the previous tail to it,
   'and returns the address of the new node
   dim as node ptr newnode = allocate(sizeof(node))
   tail->nxt = newnode
   newnode->nxt = NULL
   newnode->word = word
   return newnode

end function

function crunch( word as string ) as string

   dim as string ret = ""
   for i as uinteger = 1 to len(word) step 2
       ret += mid(word,i,1)
   next i
   return ret

end function

function length( word as string ) as uinteger

   'necessary replacement for the built-in len function, which in this
   'case would always return 32
   for i as uinteger = 1 to 32
       if asc(mid(word,i,1)) = 0 then return i-1
   next i
   return 999

end function

dim as string word dim as node ptr tail = allocate( sizeof(node) ) dim as node ptr head = tail, curr = head, currj tail->nxt = NULL tail->word = "XXXXHEADER"

open "unixdict.txt" for input as #1 while true

   line input #1, word
   if word = "" then exit while
   tail = addword( tail, word )

wend close #1

while curr->nxt <> NULL

   if length(curr->word) > 8 then word = crunch( curr->word ) else goto nextword
   currj = head
   while currj->nxt <> NULL
       if word = currj->word then print left(curr->word,length(curr->word));"   --->   ";word
       currj = currj->nxt
   wend
   nextword:
   curr = curr->nxt

wend</lang>

Output:
barbarian   --->   brain
childbear   --->   cider
corrigenda   --->   cried
gargantuan   --->   grata
headdress   --->   hades
palladian   --->   plain
propionate   --->   point
salvation   --->   slain
siltation   --->   slain
slingshot   --->   sight
statuette   --->   saute
supersede   --->   spree
supervene   --->   spree
terminable   --->   trial

And to discourage the creation of a whole new task for the even words, here they are. It requires only changing a 1 to a 2 in line 20, and an 8 to a 9 in line 50.

cannonball   --->   annal
importation   --->   motto
psychopomp   --->   scoop
starvation   --->   train
upholstery   --->   posey

Go

<lang go>package main

import (

   "bytes"
   "fmt"
   "io/ioutil"
   "log"
   "sort"
   "strings"

)

func main() {

   wordList := "unixdict.txt"
   b, err := ioutil.ReadFile(wordList)
   if err != nil {
       log.Fatal("Error reading file")
   }
   bwords := bytes.Fields(b)
   words := make([]string, len(bwords))
   for i, bword := range bwords {
       words[i] = string(bword)
   }
   count := 0
   fmt.Println("The odd words with length > 4 in", wordList, "are:")
   for _, word := range words {
       rword := []rune(word) // in case any non-ASCII
       if len(rword) > 8 {
           var sb strings.Builder
           for i := 0; i < len(rword); i += 2 {
               sb.WriteRune(rword[i])
           }
           s := sb.String()
           idx := sort.SearchStrings(words, s)      // binary search
           if idx < len(words) && words[idx] == s { // check not just an insertion point
               count = count + 1
               fmt.Printf("%2d: %-12s -> %s\n", count, word, s)
           }
       }
   }

}</lang>

Output:
The odd words with length > 4 in unixdict.txt are:
 1: barbarian    -> brain
 2: childbear    -> cider
 3: corrigenda   -> cried
 4: gargantuan   -> grata
 5: headdress    -> hades
 6: palladian    -> plain
 7: propionate   -> point
 8: salvation    -> slain
 9: siltation    -> slain
10: slingshot    -> sight
11: statuette    -> saute
12: supersede    -> spree
13: supervene    -> spree
14: terminable   -> trial

Java

<lang java>import java.io.*; import java.util.*;

public class OddWords {

   public static void main(String[] args) {
       try {
           Set<String> dictionary = new TreeSet<>();
           final int minLength = 5;
           String fileName = "unixdict.txt";
           if (args.length != 0)
               fileName = args[0];
           try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
               String line;
               while ((line = reader.readLine()) != null) {
                   if (line.length() >= minLength)
                       dictionary.add(line);
               }
           }
           StringBuilder word1 = new StringBuilder();
           StringBuilder word2 = new StringBuilder();
           List<StringPair> evenWords = new ArrayList<>();
           List<StringPair> oddWords = new ArrayList<>();
           for (String word : dictionary) {
               int length = word.length();
               if (length < minLength + 2 * (minLength/2))
                   continue;
               word1.setLength(0);
               word2.setLength(0);
               for (int i = 0; i < length; ++i) {
                   if ((i & 1) == 0)
                       word1.append(word.charAt(i));
                   else
                       word2.append(word.charAt(i));
               }
               String oddWord = word1.toString();
               String evenWord = word2.toString();
               if (dictionary.contains(oddWord))
                   oddWords.add(new StringPair(word, oddWord));
               if (dictionary.contains(evenWord))
                   evenWords.add(new StringPair(word, evenWord));
           }
           System.out.println("Odd words:");
           printWords(oddWords);
           System.out.println("\nEven words:");
           printWords(evenWords);
       } catch (Exception e)  {
           e.printStackTrace();
       }
   }
   private static void printWords(List<StringPair> strings) {
       int n = 1;
       for (StringPair pair : strings) {
           System.out.printf("%2d: %-14s%s\n", n++,
                                   pair.string1, pair.string2);
       }
   }
   private static class StringPair {
       private String string1;
       private String string2;
       private StringPair(String s1, String s2) {
           string1 = s1;
           string2 = s2;
       }
   }

}</lang>

Output:
Odd words:
 1: barbarian     brain
 2: childbear     cider
 3: corrigenda    cried
 4: gargantuan    grata
 5: headdress     hades
 6: palladian     plain
 7: propionate    point
 8: salvation     slain
 9: siltation     slain
10: slingshot     sight
11: statuette     saute
12: supersede     spree
13: supervene     spree
14: terminable    trial

Even words:
 1: cannonball    annal
 2: importation   motto
 3: psychopomp    scoop
 4: starvation    train
 5: upholstery    posey

Julia

See Alternade_words#Julia for the foreachword function. <lang julia>isoddword(w, d) = (o = mapreduce(i -> w[i], *, 1:2:length(w)); haskey(d, o) ? rpad(w, 16) * ": " * o : "") foreachword("unixdict.txt", isoddword, minlen=9, numcols=1)

</lang>

Output:
Word source: unixdict.txt

barbarian       :  brain
childbear       :  cider
corrigenda      :  cried
gargantuan      :  grata
headdress       :  hades
palladian       :  plain
propionate      :  point
salvation       :  slain
siltation       :  slain
slingshot       :  sight
statuette       :  saute
supersede       :  spree
supervene       :  spree
terminable      :  trial


Nim

<lang Nim>import sets, strformat, sugar

const DictFile = "unixdict.txt"

let words = collect(initHashSet, for word in DictFile.lines: {word})

var count = 0 for word in DictFile.lines:

 var oddWord: string
 for i in countup(0, word.high, 2): oddWord.add word[i]  # First odd char is at index 0.
 if oddWord.len > 4 and oddWord in words:
   inc count
   echo &"{count:2}: {word:12} →  {oddWord}"</lang>
Output:
 1: barbarian    →  brain
 2: childbear    →  cider
 3: corrigenda   →  cried
 4: gargantuan   →  grata
 5: headdress    →  hades
 6: palladian    →  plain
 7: propionate   →  point
 8: salvation    →  slain
 9: siltation    →  slain
10: slingshot    →  sight
11: statuette    →  saute
12: supersede    →  spree
13: supervene    →  spree
14: terminable   →  trial

Perl

<lang perl>#!/usr/bin/perl

@ARGV = 'unixdict.txt'; chomp( my @words = <> ); my %dict; @dict{ grep length > 4, @words} = (); for ( @words )

 {
 my $oddword = s/(.).?/$1/gr;
 exists $dict{$oddword} and print " $_ $oddword\n";
 }</lang>
Output:
 barbarian brain
 childbear cider
 corrigenda cried
 gargantuan grata
 headdress hades
 palladian plain
 propionate point
 salvation slain
 siltation slain
 slingshot sight
 statuette saute
 supersede spree
 supervene spree
 terminable trial

Phix

<lang Phix>sequence words = get_text("demo/unixdict.txt",GT_LF_STRIPPED) function odd(integer /*ch*/, idx) return remainder(idx,2)=1 end function function oddch(string word) return filter(word,odd) end function function over4(string word) return length(word)>4 end function words = filter(filter(apply(words,oddch),over4),"in",words) printf(1,"%d odd words found: %s\n",{length(words),join(shorten(words,"",3),", ")})</lang>

Output:
14 odd words found: brain, cider, cried, ..., spree, spree, trial

Alternative

Slightly more traditional, same output. <lang Phix>sequence words = get_text("demo/unixdict.txt",GT_LF_STRIPPED),

        res = {}

for i=1 to length(words) do

   string word = words[i], wodd = ""
   for oddchar=1 to length(word) by 2 do
       wodd &= word[oddchar]
   end for
   if length(wodd)>4 
   and find(wodd,words) then
       res = append(res,wodd)
   end if

end for printf(1,"%d odd words found: %s\n",{length(res),join(shorten(res,"",3),", ")})</lang>

Quackery

<lang Quackery> [ stack ] is sift.test ( --> s )

 protect sift.test
 [ ]'[ sift.test put
   [] [] rot 
   witheach
     [ sift.test share do iff
         [ nested join ]
       else 
         [ swap dip 
           [ nested join ] ] ]
    sift.test release ]         is siftwith   (   [ --> [ [ )
 [ 1 & ]                        is odd        (   n --> b   )
 [ stack ]                      is dict       (     --> s   )
 [ dict share
  dup dip find found ]          is indict     (   $ --> b   )
 $ "unixdict.txt" sharefile drop
 nest$ siftwith [ dup size 4 > ]
 nip dict put

 dict share 
 siftwith [ dup size 8 > ]
 nip
 witheach
 [ siftwith [ i^ odd ]
   drop
   dup indict iff
     [ echo$ cr ]
   else drop ]
 dict release</lang>
Output:
brain
cider
cried
grata
hades
plain
point
slain
slain
sight
saute
spree
spree
trial

Raku

<lang perl6>my %words = 'unixdict.txt'.IO.slurp.words.map: * => 1;

my (@odds, @evens);

for %words {

   next if .key.chars < 9;
   my $odd  = .key.comb[0,2 … *].join;
   @odds.push(.key => $odd) if %words{$odd} and $odd.chars > 4;
   my $even = .key.comb[1,3 … *].join;
   @evens.push(.key => $even) if %words{$even} and $even.chars > 4;

}

.put for flat 'Odd words > 4:', @odds.sort;

.put for flat "\nEven words > 4:", @evens.sort;</lang>

Output:
Odd words > 4:
barbarian	brain
childbear	cider
corrigenda	cried
gargantuan	grata
headdress	hades
palladian	plain
propionate	point
salvation	slain
siltation	slain
slingshot	sight
statuette	saute
supersede	spree
supervene	spree
terminable	trial

Even words > 4:
cannonball	annal
importation	motto
psychopomp	scoop
starvation	train
upholstery	posey

REXX

Any words longer than ten characters are truncated in the output.

version 1

<lang rwxx>/* REXX */ fid='d:\unix.txt' ww.=0 /* ww.* the words to be analyzed */ w.=0 /* w.word = 1 if word is in unix.txt */ Do While lines(fid)>0

 l=linein(fid)     /* a word                 */
 ll=length(l)
 w.l=1             /*  word is in unix.txt   */
 If ll>=9 Then Do  /* worth to be analyzed   */
   z=ww.0+1        /* add it to the list     */
   ww.z=l
   ww.0=z
   End
 End

n=0 Do i=1 To ww.0

 wodd=wodd(ww.i)
 If w.wodd Then Do
   n=n+1
   Say format(n,3) left(ww.i,10) wodd
   End
 End

Exit wodd: Procedure /* use odd indexed letters */

 Parse Arg w
 wo=
 Do i=1 To length(w)
   If i//2=1 Then
     wo=wo||substr(w,i,1)
   End
 Return wo</lang>
Output:
  1 barbarian  brain
  2 childbear  cider
  3 corrigenda cried
  4 gargantuan grata
  5 headdress  hades
  6 palladian  plain
  7 propionate point
  8 salvation  slain
  9 siltation  slain
 10 slingshot  sight
 11 statuette  saute
 12 supersede  spree
 13 supervene  spree
 14 terminable trial

version 2, caseless

This REXX version doesn't care what order the words in the dictionary are in,   nor does it care what
case  (lower/upper/mixed)  the words are in,   the search for alternades is   caseless.

It also allows the minimum length to be specified on the command line (CL) as well as the dictionary file identifier. <lang rexx>/*REXX program finds all the caseless "odd words" (within an identified dictionary). */ parse arg minL iFID . /*obtain optional arguments from the CL*/ if minL== | minL=="," then minL= 5 /*Not specified? Then use the default.*/ if iFID== | iFID=="," then iFID='unixdict.txt' /* " " " " " " */ @.= /*default value of any dictionary word.*/

          do #=1  while lines(iFID)\==0         /*read each word in the file  (word=X).*/
          x= strip( linein( iFID) )             /*pick off a word from the input line. */
          $.#= x;       upper x;       @.x= .   /*save: original case and the semaphore*/
          end   /*#*/                           /* [↑]   semaphore name is uppercased. */
  1. = # - 1 /*adjust word count because of DO loop.*/

minW= minL * 2 - 1 /*minimum width of a word to be usable.*/ say copies('─', 30) # "words in the dictionary file: " iFID say finds= 0 /*count of the "odd words" found. */

       do j=1  for #;         L= length($.j)    /*process all the words that were found*/
       if L<minW  then iterate                  /*Is word too short?   Then ignore it. */
       ow=                                      /*initialize the  "odd word".          */
                  do k=1  by 2  to  L           /*only use odd indexed letters in word.*/
                  ow= ow  ||  substr($.j, k, 1) /*construct the  "odd word".           */
                  end   /*k*/
       owU= ow;               upper owU         /*uppercase the odd word to be caseless*/
       if @.owU==  then iterate               /*if not extant,  then skip this word. */
       finds= finds + 1                         /*bump the count of "odd words" found. */
       say right(left($.j, 20), 24) left(ow, 9) /*indent original word for readability.*/
       end        /*j*/
                                                /*stick a fork in it,  we're all done. */

say copies('─', 30) finds ' "odd words" found with a minimum length of ' minL</lang>

output   when using the default input:
────────────────────────────── 25104 words in the dictionary file:  unixdict.txt
    barbarian            brain
    childbear            cider
    corrigenda           cried
    gargantuan           grata
    headdress            hades
    palladian            plain
    propionate           point
    salvation            slain
    siltation            slain
    slingshot            sight
    statuette            saute
    supersede            spree
    supervene            spree
    terminable           trial
────────────────────────────── 14  "odd words" found with a minimum length of  5

Ring

<lang ring> cStr = read("unixdict.txt") wordList = str2list(cStr) num = 0

see "Odd words are:" + nl

for n = 1 to len(wordList)

   strWord = ""
   len = len(wordList[n])
   for m = 1 to len step 2
       strWord = strWord + wordList[n][m]
   next
   ind = find(wordList,strWord) 
   if ind > 0  and len(strWord) > 4
      num = num + 1
      see "" + num + ". " + wordList[n] + " >> " + strWord + nl
   ok

next </lang> Output:

Odd words are:
1. barbarian >> brain
2. childbear >> cider
3. corrigenda >> cried
4. gargantuan >> grata
5. headdress >> hades
6. palladian >> plain
7. propionate >> point
8. salvation >> slain
9. siltation >> slain
10. slingshot >> sight
11. statuette >> saute
12. supersede >> spree
13. supervene >> spree
14. terminable >> trial

Rust

<lang rust>use std::collections::BTreeSet; use std::fs::File; use std::io::{self, BufRead};

fn load_dictionary(filename: &str, min_length: usize) -> std::io::Result<BTreeSet<String>> {

   let file = File::open(filename)?;
   let mut dict = BTreeSet::new();
   for line in io::BufReader::new(file).lines() {
       let word = line?;
       if word.len() >= min_length {
           dict.insert(word);
       }
   }
   Ok(dict)

}

fn print_words(words: &[(&String, String)]) {

   for (i, (a, b)) in words.iter().enumerate() {
       println!("{:2}: {:<14}{}", i + 1, a, b);
   }

}

fn main() {

   let min_length = 5;
   match load_dictionary("unixdict.txt", min_length) {
       Ok(dictionary) => {
           let mut odd_words = Vec::new();
           let mut even_words = Vec::new();
           for word in &dictionary {
               if word.len() < min_length + 2 * (min_length / 2) {
                   continue;
               }
               let mut odd_word = String::new();
               let mut even_word = String::new();
               for (i, c) in word.chars().enumerate() {
                   if (i & 1) == 0 {
                       odd_word.push(c);
                   } else {
                       even_word.push(c);
                   }
               }
               if dictionary.contains(&odd_word) {
                   odd_words.push((word, odd_word));
               }
               if dictionary.contains(&even_word) {
                   even_words.push((word, even_word));
               }
           }
           println!("Odd words:");
           print_words(&odd_words);
           println!("\nEven words:");
           print_words(&even_words);
       }
       Err(error) => eprintln!("{}", error),
   }

}</lang>

Output:
Odd words:
 1: barbarian     brain
 2: childbear     cider
 3: corrigenda    cried
 4: gargantuan    grata
 5: headdress     hades
 6: palladian     plain
 7: propionate    point
 8: salvation     slain
 9: siltation     slain
10: slingshot     sight
11: statuette     saute
12: supersede     spree
13: supervene     spree
14: terminable    trial

Even words:
 1: cannonball    annal
 2: importation   motto
 3: psychopomp    scoop
 4: starvation    train
 5: upholstery    posey

Swift

<lang swift>import Foundation

let minLength = 5

func loadDictionary(_ path: String) throws -> Set<String> {

   let contents = try String(contentsOfFile: path, encoding: String.Encoding.ascii)
   return Set<String>(contents.components(separatedBy: "\n").filter{$0.count >= minLength})

}

func pad(string: String, width: Int) -> String {

   return string.count >= width ? string
       : string + String(repeating: " ", count: width - string.count)

}

func printWords(words: [(String,String)]) {

   for (n, (word1, word2)) in words.enumerated() {
       print("\(String(format: "%2d", n + 1)): \(pad(string: word1, width: 14))\(word2)")
   }

}

do {

   let dictionary = try loadDictionary("unixdict.txt")
   var oddWords: [(String, String)] = []
   var evenWords: [(String, String)] = []
   for word in dictionary {
       if word.count < minLength + 2*(minLength/2) {
           continue
       }
       var oddWord = ""
       var evenWord = ""
       for (i, c) in word.enumerated() {
           if (i & 1) == 0 {
               oddWord.append(c)
           } else {
               evenWord.append(c)
           }
       }
       if dictionary.contains(oddWord) {
           oddWords.append((word, oddWord))
       }
       if dictionary.contains(evenWord) {
           evenWords.append((word, evenWord))
       }
   }
   oddWords.sort(by: {$0.0 < $1.0})
   evenWords.sort(by: {$0.0 < $1.0})
   print("Odd words:")
   printWords(words: oddWords)
   print("\nEven words:")
   printWords(words: evenWords)

} catch {

   print(error.localizedDescription)

}</lang>

Output:
Odd words:
 1: barbarian     brain
 2: childbear     cider
 3: corrigenda    cried
 4: gargantuan    grata
 5: headdress     hades
 6: palladian     plain
 7: propionate    point
 8: salvation     slain
 9: siltation     slain
10: slingshot     sight
11: statuette     saute
12: supersede     spree
13: supervene     spree
14: terminable    trial

Even words:
 1: cannonball    annal
 2: importation   motto
 3: psychopomp    scoop
 4: starvation    train
 5: upholstery    posey

Wren

Library: Wren-fmt
Library: Wren-sort
Library: Wren-trait

<lang ecmascript>import "io" for File import "/fmt" for Fmt import "/sort" for Find import "/trait" for Stepped

var wordList = "unixdict.txt" // local copy var words = File.read(wordList).trimEnd().split("\n") var count = 0 System.print("The odd words with length > 4 in %(wordList) are:") for (word in words) {

   if (word.count > 8) {
       var s = ""
       var chars = word.toList // in case any non-ASCII
       for (i in Stepped.new(0...chars.count, 2)) s = s + chars[i]
       if (Find.first(words, s) >= 0) { // binary search
           count = count + 1
           Fmt.print("$2d: $-12s -> $s", count, word, s)
       }
   }

}</lang>

Output:
The odd words with length > 4 in unixdict.txt are:
 1: barbarian    -> brain
 2: childbear    -> cider
 3: corrigenda   -> cried
 4: gargantuan   -> grata
 5: headdress    -> hades
 6: palladian    -> plain
 7: propionate   -> point
 8: salvation    -> slain
 9: siltation    -> slain
10: slingshot    -> sight
11: statuette    -> saute
12: supersede    -> spree
13: supervene    -> spree
14: terminable   -> trial

XPL0

<lang XPL0>string 0; \use zero-terminated strings int Dict(26000); \pointers to words (enough for unixdict.txt) int DictSize; \actual number of pointers in Dict

func StrCmp(A, B); \Compare string A to B char A, B; \Returns: >0 if A>B, =0 if A=B, and <0 if A>1 do

       [if A(I) # B(I) then return A(I) - B(I);
        if A(I) = 0 then return 0;
       ];

]; \StrCmp

func LookUp(Word); \Return 'true' if Word is in Dict char Word; int Lo, Hi, I, Cmp; [Lo:= 0; Hi:= DictSize-1; loop [I:= (Lo+Hi) / 2; \binary search

       Cmp:= StrCmp(Word, Dict(I));
       if Cmp < 0 then Hi:= I-1 else Lo:= I+1;
       if Cmp = 0 then return true;
       if Lo > Hi then return false;
       ];

]; \LookUp

int I, I0, DI, Ch, Count; char Word, Alt0(25); def Tab=$09, LF=$0A, CR=$0D, EOF=$1A;

[FSet(FOpen("unixdict.txt", 0), ^I); \load dictionary OpenI(3); \assume alphabetical order and all lowercase DI:= 0; \ignore non-alpha characters: 0..9, ' and & repeat Dict(DI):= Reserve(0); \get pointer to memory used to store Word

       Word:= Dict(DI);
       I:= 0;
       loop    [repeat Ch:= ChIn(3) until Ch # CR;     \remove possible CR
               if Ch=LF or Ch=EOF then quit;
               Word(I):= Ch;
               I:= I+1;
               ];
       Word(I):= 0;            \terminate Word string
       I:= Reserve(I+1);       \reserve memory used for Word
       DI:= DI+1;              \next dictionary entry

until Ch = EOF; DictSize:= DI;

DI:= 0; Count:= 0; repeat Word:= Dict(DI); \print out all odd words

       I:= 0;  I0:= 0;
       loop    [Ch:= Word(I);
               if Ch = 0 then quit;
               if (I&1) = 0 then [Alt0(I0):= Ch;  I0:= I0+1];
               I:= I+1;
               ];
       if I >= 9 then          \Word must have at least 9 chars
               [Alt0(I0):= 0;
               if LookUp(Alt0) then
                       [Count:= Count+1;
                       IntOut(0, Count);  ChOut(0, Tab);
                       Text(0, Word);  ChOut(0, Tab);
                       Text(0, Alt0);  ChOut(0, Tab);
                       CrLf(0);
                       ];
               ];
       DI:= DI+1;

until DI >= DictSize; ]</lang>

Output:
1       barbarian       brain   
2       childbear       cider   
3       corrigenda      cried   
4       gargantuan      grata   
5       headdress       hades   
6       palladian       plain   
7       propionate      point   
8       salvation       slain   
9       siltation       slain   
10      slingshot       sight   
11      statuette       saute   
12      supersede       spree   
13      supervene       spree   
14      terminable      trial