Better idea for double list comprehension?

CJS Prometheus85 at hotmail.com
Sat Jan 18 14:04:59 PST 2014


>
> import std.stdio, std.conv, std.algorithm, std.array;
>
> string[] cross(in string A, in string B) {
>     return cartesianProduct(A, B).map!(ab => ab[].text).array;
> }
>
> void main() {
>     cross("ab", "12").writeln;
> }
>
>
> But note that currently cartesianProduct doesn't return the 
> pairs in a natural order.
>
> cross() should be pure.

Great. Here's a similar follow-up question. I'm trying to 
reproduce Peter Novig's Python code for solving Sudoku in D 
(http://norvig.com/sudoku.html). As a way to understand both his 
code and D/Phobos better. The entire code chunk I'm working on 
now is

def cross(A, B):
     "Cross product of elements in A and elements in B."
     return [a+b for a in A for b in B]

digits   = '123456789'
rows     = 'ABCDEFGHI'
cols     = digits
squares  = cross(rows, cols)
unitlist = ([cross(rows, c) for c in cols] +
             [cross(r, cols) for r in rows] +
             [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs 
in ('123','456','789')])
units = dict((s, [u for u in unitlist if s in u])
              for s in squares)
peers = dict((s, set(sum(units[s],[]))-set([s]))
              for s in squares)

Unfortunately my current best attemp doesn't compile:

import std.stdio : writeln;
import std.range : chunks, chain;
import std.algorithm;
import std.array;
import std.conv;

auto cross(R1, R2)(in R1 A, in R2 B){
     return cartesianProduct(A,B).map!(ab => ab[].text).array;
}


void main(){
     string letters = "ABCDEFGHI";
     string digits = "123456789";

     auto cols = digits;
     auto rows = letters;

     auto squares = cross(rows, cols);
     string[][] unitlist;
     foreach(c; cols){
         unitlist ~= cross(rows, to!string(c));
     }
     foreach(r; rows){
         unitlist ~= cross(to!string(r), cols);
     }
     foreach(r; chunks(rows, 3)){
         foreach(c; chunks(cols, 3)){
             unitlist ~= cross(to!string(r),to!string(c));
         }
     }

     string[][][string] units;
     string[][string] peers;

     foreach(s; squares){
         units[s] = filter!(x=>any!(y=>(s==y)))(unitlist);
     }

     foreach(s; squares){
         peers[s] = remove(chain(units[s]), s);
     }

}

Up until units and peers are defined it works, but I find the 
to!string conversions ugly. Because of cross being templated I 
don't think they should be necessary. Taking the cartesian 
product of a string with a character seems like a reasonable 
request. Simialrly, so does taking the cartesian product of a 
string with a range of characters.

For the associative arrays I'm unsure I have the correct calls, 
but they looked reasonable. Any suggestions?




More information about the Digitalmars-d-learn mailing list