5
$\begingroup$

I have a very poorly-formed list of football scores:

{{"Glenville State", "GLN 44", "9", " Northwood (MI)"}
 {" Missouri Southern State", "24", "Northwest Missouri State", "NOR 31"}, 
 {"SDST 45", " South Dakota State", "Western Oregon", "7"}, 
 {" Central Oklahoma", "CEN 24", "Nebraska-Kearney", "21"},
 {"17", " University of Rochester (NY)", "Utica", "UTI 20"}}

I'd like to clean up this list so that each game has the same format {team1,score1,team 2,score2} which would give:

{{"Glenville State", "44", " Northwood (MI)", "9"}
 {"Missouri Southern State", "24", "Northwest Missouri State", "31"}
 {"South Dakota State", "45", "Western Oregon", "7"}
 {"Central Oklahoma", "24", "Nebraska-Kearney", "21"}
 {"University of Rochester (NY)", "17", "Utica", "20"}}

As can be seen, the all-caps abbreviations get deleted. Is there a way to do this without writing rules for each variant?

$\endgroup$

5 Answers 5

6
$\begingroup$
table = {{"Glenville State", "GLN 44", "9", " Northwood (MI)"} , 
  {" Missouri Southern State", "24", "Northwest Missouri State", "NOR 31"},
  {"SDST 45", " South Dakota State", "Western Oregon", "7"},
  {" Central Oklahoma", "CEN 24", "Nebraska-Kearney", "21"},
  {"17", " University of Rochester (NY)", "Utica", "UTI 20"}};


ClearAll[scores, teams]

scores =  Apply[Join] @*
 Map[StringCases[(LetterCharacter .. ~~ " ")|StartOfString
   ~~ n : DigitCharacter .. :> n]]

teams = Apply[Join] @*
  Map[StringCases[StartOfString ~~ Except[DigitCharacter] .. ~~ EndOfString]]

Map[Riffle[teams @ #, scores @ #] &] @ Map[StringTrim] @ table
{{"Glenville State", "44", "Northwood (MI)", "9"},   
 {"Missouri Southern State", "24", "Northwest Missouri State", "31"},  
 {"South Dakota State", "45", "Western Oregon", "7"},   
 {"Central Oklahoma", "24", "Nebraska-Kearney", "21"},   
 {"University of Rochester (NY)", "17", "Utica", "20"}}
$\endgroup$
3
$\begingroup$
Riffle @@@ 
KeyValueMap[If[#1, Flatten[StringCases[#2, NumberString]], StringTrim[#2]] &] /@
KeySort /@ 
(GroupBy[#, StringContainsQ[NumberString]] & /@ rawScoreData)

This assumes that team names never contain numbers (and that scores always do), that there are exactly two teams and two scores in each record, that teams and scores are ordered respectively (but otherwise order doesn't matter).

$\endgroup$
1
  • $\begingroup$ Thanks to you both! $\endgroup$
    – Suite401
    Sep 8, 2023 at 23:05
3
$\begingroup$
list = {{"Glenville State", "GLN 44", "9", " Northwood (MI)"}, 
{" Missouri Southern State", "24", "Northwest Missouri State", "NOR 31"},
{"SDST 45", " South Dakota State", "Western Oregon", "7"}, 
{" Central Oklahoma", "CEN 24", "Nebraska-Kearney", "21"}, 
{"17", " University of Rochester (NY)", "Utica", "UTI 20"}};

scores = Flatten[StringCases[#, RegularExpression["\\d+"]]] & /@ list

{{"44", "9"}, {"24", "31"}, {"45", "7"}, {"24", "21"}, {"17", "20"}}

teams = Flatten[
    StringCases[#, RegularExpression["(?i)[a-z]+\\D+$"]]] & /@ list

{{"Glenville State", "Northwood (MI)"}, {"Missouri Southern State", "Northwest Missouri State"}, {"South Dakota State", "Western Oregon"}, {"Central Oklahoma", "Nebraska-Kearney"}, {"University of Rochester (NY)", "Utica"}}

Riffle @@@ Transpose[{teams, scores}]

{{"Glenville State", "44", "Northwood (MI)", "9"}, {"Missouri Southern State", "24", "Northwest Missouri State", "31"}, {"South Dakota State", "45", "Western Oregon", "7"}, {"Central Oklahoma", "24", "Nebraska-Kearney", "21"}, {"University of Rochester (NY)", "17", "Utica", "20"}}

$\endgroup$
3
$\begingroup$

Using Map and MapAt:

Clear["Global`*"];

table = {{"Glenville State", "GLN 44", "9", 
    " Northwood (MI)"}, {" Missouri Southern State", "24", 
    "Northwest Missouri State", "NOR 31"}, {"SDST 45", 
    " South Dakota State", "Western Oregon", 
    "7"}, {" Central Oklahoma", "CEN 24", "Nebraska-Kearney", 
    "21"}, {"17", " University of Rochester (NY)", "Utica", 
    "UTI 20"}};

res = Map[Partition[#, 2] &, table, {1}] // 
     Map[SortBy[#, StringContainsQ[NumberString]] &, #, {2}] & //
    MapAt[
      StringReplace[Except[DigitCharacter] :> ""], #, {All, All, 
       2}] & //
   Map[Flatten, #, {1}] & //
  Map[StringTrim]

Using SequenceReplace:

SequenceReplace[#, { 
     OrderlessPatternSequence[x_, y_] /; 
      StringFreeQ[x, NumberString] && 
       StringContainsQ[y, NumberString]} :> 
    Sequence @@ {StringTrim@x, StringTrim@
       StringReplace[y, Except[DigitCharacter] :> ""]}
   ] & /@ table

Result

{{"Glenville State", "44", "Northwood (MI)", "9"}, {"Missouri Southern State", "24", "Northwest Missouri State", "31"}, {"South Dakota State", "45", "Western Oregon", "7"}, {"Central Oklahoma", "24", "Nebraska-Kearney", "21"}, {"University of Rochester (NY)", "17", "Utica", "20"}}

$\endgroup$
3
$\begingroup$

Although it is probably impossible to cover all situations with a single regex, assuming that the letters that need to be removed from the scores are capitals and always occur as a prefix, and that the length of the score (in digits) is less than that of the team name, one possibility it to use StringSplit combined with a RegularExpression that incorporates a positive lookahead.

(Thanks to Alexey Popkov for the link to positive lookaheads)

sortFn=Flatten@BlockMap[ReverseSortBy[StringLength],#,2]&;

splitFn=StringSplit[StringTrim@#,
  RegularExpression["(^[A-Z\\s]{1,5})(?=[0-9]{1,2})"]]&;

(sortFn@*splitFn)/@scr//Tableform//TeXForm

$ \begin{array}{lrlr}\text{Glenville State}&44&\text{Northwood (MI)}&9\\\text{Missouri Southern State}&24&\text{Northwest Missouri State}&31\\\text{South Dakota State}&45&\text{Western Oregon}&7\\\text{Central Oklahoma}&24&\text{Nebraska-Kearney}&21\\\text{University of Rochester (NY)}&17&\text{Utica}&20\\\end{array} $

This works reasonably well even when the team name contains digits:

(sortFn@*splitFn)/@scralt//TableForm//TeXForm

$ \begin{array}{lrlr}\text{1 Glenville State 1A}&44&\text{2 Northwood (MI) 2B}&9\\\text{3 Missouri Southern State C3}&24&\text{4 Northwest Missouri State D44}&31\\\text{5 South Dakota State A55}&45&\text{6 Western Oregon AA66}&7\\\text{7 Central Oklahoma}&24&\text{8 Nebraska-Kearney}&21\\\text{9 University of Rochester (NY)}&17&\text{10 Utica}&20\\\end{array} $

If some scores contain suffixes rather than prefixes, then one possibility is a targeted removal, provided that the table is first properly sorted:

replaceFn=StringReplace[#,RegularExpression["([0-9]+)([A-Z\\s]+)"]->"$1"]&;

MapAt[replaceFn,sortFn@*Catenate/@splitFn/@scralt2,
  {{All,2},{All,4}}]//TableForm//TeXForm

$ \begin{array}{lrlr}\text{1 Glenville State 1A}&44&\text{2 Northwood (MI) 2B}&9\\\text{3 Missouri Southern State C3}&24&\text{4 Northwest Missouri State D44}&31\\\text{5 South Dakota State A55}&45&\text{6 Western Oregon AA66}&7\\\text{7 Central Oklahoma}&24&\text{8 Nebraska-Kearney}&21\\\text{9 University of Rochester (NY)}&17&\text{10 Utica}&20\\\end{array} $

where

scr={{"Glenville State", "GLN 44", "9", " Northwood (MI)"},
 {" Missouri Southern State", "24", "Northwest Missouri State", "NOR 31"}, 
 {"SDST 45", " South Dakota State", "Western Oregon", "7"}, 
 {" Central Oklahoma", "CEN 24", "Nebraska-Kearney", "21"},
 {"17", " University of Rochester (NY)", "Utica", "UTI 20"}};

scralt={{"1 Glenville State 1A", "GLN 44", "9", "2 Northwood (MI) 2B"},
 {"3 Missouri Southern State C3", "H24", "4 Northwest Missouri State D44", "NOR 31"}, 
 {"SDST 45", "5 South Dakota State A55", "6 Western Oregon AA66", "A7"}, 
 {"7 Central Oklahoma", "CEN 24", "8 Nebraska-Kearney", "21"},
 {"17", "9 University of Rochester (NY)", "10 Utica", "UTI 20"}};

scralt2={{"1 Glenville State 1A", "44 GLN", "9", "2 Northwood (MI) 2B"},
 {"3 Missouri Southern State C3", "24H", "4 Northwest Missouri State D44", "NOR 31"}, 
 {"SDST 45", "5 South Dakota State A55", "6 Western Oregon AA66", "A7"}, 
 {"7 Central Oklahoma", "CEN 24", "8 Nebraska-Kearney", "21"},
 {"17", "9 University of Rochester (NY)", "10 Utica", "UTI 20"}};

Original Answer

Assuming that the score is between 1 and 2 digit characters, that a prefix of between 3 and 5 uppercase characters/space (if a prefix occurs) needs to be removed, and that the StringLength of the (truncated) score is less that that of the team name:

(Flatten@BlockMap[ReverseSortBy[StringLength],#,2])&@StringReplace[StringTrim@#, 
    RegularExpression["([A-Z\\s]{3,5})([0-9]{1,2})"]:>"$2"]&/@scr


(* {
    {Glenville State,44,Northwood (MI),9},
    {Missouri Southern State,24,Northwest Missouri State,31},
    {South Dakota State,45,Western Oregon,7},
    {Central Oklahoma,24,Nebraska-Kearney,21},
    {University of Rochester (NY),17,Utica,20}
   } *) 

If the uppercase characters/space may occur as a prefix or a suffix, maybe:

(Flatten@BlockMap[ReverseSortBy[StringLength],#,2])&@StringReplace[StringTrim@#, 
    {RegularExpression["([A-Z\\s]{3,5})([0-9]{1,2})"]:>"$2",
     RegularExpression["([0-9]{1,2})([A-Z\\s]{3,5})"]:>"$1"}
    ]&/@scrAlt

(* {
    {Glenville State,44,Northwood (MI),9},
    {Glenville State,44,Northwood (MI),9}
   } *)
 

where

scrAlt={
        {"Glenville State", "GLN 44", "9", " Northwood (MI)"},
        {"Glenville State", "44 GLN", "9", " Northwood (MI)"}
       }
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.