我正在尝试将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
(SO已经搞砸了我的SML的缩进,对不起!)
答案 0 :(得分:3)
如果您的列表是常规的(列表中的每个列表具有相同的长度),您所描述的内容听起来像矩阵转置。使用Standard 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)
答案 1 :(得分:2)
这是内心zipElement
的想法
所有学分都归Dan Grossman所有
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
我希望你能想出自己将元组转换为列表的方法。