2

我正在尝试将 Java 代码中的嵌套 for 循环转换为 SML。我将有一个格式列表 [[a, b, c], [d, e, f], [g, h, i]] 并且我希望这个函数给我一个表单列表 [ [a, d, g], [b, e, h], [c, f, i]]。每个列表的长度会有所不同,我需要避免使用任何可变数据类型。到目前为止我的代码是这样的——底部pointFromList获取每个内部列表并将其放入我在其他地方定义的记录中。

我遇到的问题是下面的代码不会终止。查看调试输出,它在所有zipElement ([], xs::xss, accY, accX)调用中都能正常工作,但在那之后它会在某个地方中断。我是 SML 的新手,我完全被难住了。

fun zipListToPoints (featuress : real list list) = 
    let
    fun zipElement ([], [], accY, []) = 
        accY
      | zipElement ([], [], accY, accX) =      
        zipElement(rev(accX), rev(accY), [], [])
      | zipElement ([], xs::xss, accY, accX) = 
        zipElement([], xss, [hd(xs)]::accY, tl(xs)::accX)
      | zipElement (ys::yss, xs::xss, accY, accX) =
        zipElement (yss, xss, (hd(xs)::ys)::accY, tl(xs)::accX)
    val numFeatures = length(hd(featuress))
    val zippedList = zipElement([], featuress, [], [])
    in
    map pointFromList zippedList
    end
end 

更大的背景是我有一个point带有标签的记录类型features : real list。为了在对数据进行一些分析之前对其进行规范化,我需要features对每个点的列表的第 i 个元素执行操作。原始 Java 如下所示:

for(i=0;i<Points.length(); i++){
    oneFeature = new float[Points.getNumberOfFeatures()];

    for(j=0; j<Points.getNumberOfFeatures(); j++){
    oneFeature[j] = Points[j].getFeature(i);
    }

    normalizedData = new float[Points.getNumberOfFeatures()];
    normalizedData = normalize(oneFeature);

    for(k=0; k<Points.length(); k++){
    Points[k].setFeatureList(normalizedData[k]);
    }
}

我的 SML 最终应该看起来像:

fun normalizeData (points) =
    let
    fun extractFeature (index) =
        map (fn features => sub(features, index)) #features(points)
    val listOfFeatures = 
        map extractFeature list.Tabulate (length(points), fn x => x)
    val normalizedFeatures = 
        map normalizeFeature listOfFeatures
    in
    map zipListToPoints normalizedFeatures
    end

(所以有点弄乱了我的 SML 的缩进,对不起!)

4

2 回答 2

3

如果您的列表是规则的(列表中的每个列表具有相同的长度),那么您所描述的内容听起来像是矩阵转置。这可以使用标准 ML 的列表组合器轻松实现。例如:

fun transpose [] = []
  | transpose (xss as (xs::_)) =
    List.tabulate (length xs, fn row => map (fn xs => List.nth (xs, row)) xss)

和一个演示:

- val m = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]];
> val m = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]] : int list list
- transpose m;
> val it = [[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]] : int list list

fn row => map (fn xs => List.nth (xs, row))如果给定的行未满,可以调整此辅助函数以接受。但是,如果所有行的长度不相等,则需要首先找到其中最长的,以避免丢弃大于第一行长度的位置的元素。

更新:对于大型矩阵,上述运行时间可能无法计算。下面是另一种定义方式transpose,使以前转置的元素不会一次又一次地被访问:

(* Written without pattern matching *)
fun transpose [] = []
  | transpose xs =
    if null (hd xs)
    then nil
    else map hd xs :: transpose (map tl xs)

(* Written with pattern matching *)
fun transpose [] = []
  | transpose ([]::_) = []
  | transpose xss = map hd xss :: transpose (map tl xss)
于 2013-10-18T23:20:24.577 回答
2

这是一个想法,zipElement 所有的功劳都归于丹·格罗斯曼

exception BadTriple
fun zip3 list_triple =
  case list_triple of
      ([],[],[]) => []
     | (hd1::tl1,hd2::tl2,hd3::tl3) => (hd1,hd2,hd3)::zip3(tl1,tl2,tl3)
     | _ => raise BadTriple

我希望您能自己想办法将元组转换为列表。

于 2013-10-18T18:16:03.810 回答