有没有一种编程方式来详细说明 raku 中的 'half-winds'?
Is there a programmatic way to elaborate the 'half-winds' in raku?
我有这个工作:
my %pnt = %( cardinal => <N E S W>,
ordinal => <N NE E SE S SW W NW>,
half-winds => <N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW>,
);
而且我认为可以通过编程方式创建半风数组。
然而,我的可怜尝试似乎更啰嗦:
my @cards = <N E S W>;
my @odds = <NE SE SW NW>;
my @ords = ( @cards Z @odds ).flat;
my @mids = ( ( @cards Z~ @odds ) Z ( @cards.rotate(1) Z~ @odds ) ).flat;
my @halfs = ( @ords Z @mids ).flat;
say @cards; #[N E S W]
say @ords; #[N NE E SE S SW W NW]
say @mids; #[NNE ENE ESE SSE SSW WSW WNW NNW]
say @halfs; #[N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW]
是否有更好/更简洁的选择?
即。 https://en.wikipedia.org/wiki/Points_of_the_compass
-- 季风加分!
FWIW,在这种情况下,我会考虑代码的可读性,我认为您的原始代码是您可以获得的最易读的代码。
但是如果你想获得算法,我会使用使用序列的数组切片来处理 @halfs
:
my @halfs = <N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW>;
my @mids = @halfs[1,3...*];
my @ords = @halfs[0,2...*];
my @cards = @halfs[0,4...*];
say @cards; #[N E S W]
say @ords; #[N NE E SE S SW W NW]
say @mids; #[NNE ENE ESE SSE SSW WSW WNW NNW]
say @halfs; #[N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW]
将四分之一风作为 reader 的练习,但基本上这将使用四分之一风作为基础,并以类似的方式进行处理。
假设我们有主风:
my @principals = <N NE E SE S SW W NW>;
然后我们可以按照维基百科的定义:
The name of each half-wind is constructed by combining the names of the principal winds to either side
这意味着我们要采用重叠对的主风,rotor
可以相当巧妙地做到这一点:
say @principals.rotor(2 => -1);
这给了我们:
((N NE) (NE E) (E SE) (SE S) (S SW) (SW W) (W NW))
遗憾的是,它少了一个问题,因为它错过了 (NW, N)
。好的,我们可以再次包含 N
,以牺牲一点美感为代价:
say @principals[*,0].flat.rotor(2 => -1)
给予:
((N NE) (NE E) (E SE) (SE S) (S SW) (SW W) (W NW) (NW N))
如果我们加入他们:
say @principals[*,0].flat.rotor(2 => -1).map(*.join)
我们得到:
(NNE NEE ESE SES SSW SWW WNW NWN)
这还不对,因为文章接下来要说的是:
with the cardinal wind coming first and the intercardinal wind second
基风是一个字符的,可以通过排序来固定:
say @principals[*,0].flat.rotor(2 => -1).map(*.sort(*.chars).join)
最后看起来是对的:
(NNE ENE ESE SSE SSW WSW WNW NNW)
除了半风是放在主风之间的,这可以通过压缩它们并压平结果来解决:
say flat @principals Z @principals[*,0].flat.rotor(2 => -1).map(*.sort(*.chars).join)
最后给我们:
(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW)
如果我们想让它更短,重复提到的 @principals
可以用 given
:
去掉
say flat $_ Z .[*,0].flat.rotor(2 => -1).map(*.sort(*.chars).join) given @principals
.join
就可以变成列表字符串化:
say flat $_ Z .[*,0].flat.rotor(2 => -1).map(~*.sort(*.chars)) given @principals:
并且可以使用 |
滑动运算符替换内部展平:
say flat $_ Z (|$_,.[0]).rotor(2 => -1).map(~*.sort(*.chars)) given @principals;
这仍然比首先列出它们要长,这是我可能会做的,但无论如何尝试击败它很有趣...
TL;DR 没有充分的理由,这个答案在只是 奖励积分之后。
my \quadrant = <N NbE NNE NEbN NE NEbE ENE EbN E>;
my @quarts = |quadrant,
|quadrant.reverse.map( *.trans: 'NE'=>'SE'),
|quadrant\ .map( *.trans: 'NE'=>'SW'),
|quadrant.reverse.map( *.trans: 'NE'=>'NW');
@quarts .=unique .batch(8) .map: *.say;
# (N NbE NNE NEbN NE NEbE ENE EbN)
# (E EbS ESE SEbE SE SEbS SSE SbE)
# (S SbW SSW SWbS SW SWbW WSW WbS)
# (W WbN WNW NWbW NW NWbN NNW NbW)
也许我解释了以上内容会得到一些加分:
前缀|
"slips"其右边的值;在四个象限中的每一个上使用它的净效果是结果列表包含 32 个元素而不是 4 个。
.reverse
反转列表,对应于风点符号在 NE/SW 和 SE/NW 之间反转的方式。
.map(...)
将函数或 lambda 应用于其调用列表中的每个元素。
*.trans: 'NE'=>'SE'
是一个 lambda,它将每个 N
字符音译为 S
,将每个 E
音译为 E
。冗余的 E
是第一次音译,因为它感觉比删除它更清晰;我也可以为第一象限添加 *.trans: 'NE'=>'NE'
,但感觉 less 清楚。注意。我使用 trans
是因为它简洁,但是 subst
总是可以做 trans
做的同样的事情,即使它需要更多的行,并且在 Rakudo 2020.12 subst
是几乎所有情况下都快 5 到 10 倍。
|quadrant\ .map...
中的 \
是一个“非空格”,这是一种向编译器表明它应该像斜杠和空格一样解析代码的方式那里。没有它,|
仅将 quadrant
作为其操作数。 unspace 使其将整个 quadrant.map( *.trans: 'NE'=>'SW')
表达式作为其操作数。 (在我这个答案的原始版本中,我的代码是错误的,因为我把 .map
排成一行,没有空格。)
.=unique
中的 .=
应用一个方法,然后将结果赋值给它的调用者,就地改变它。
unique
删除列表中重复的所有元素。没有它就会有四个基点的重复(<N E S W>
)。
.batch(8)
将点重新分成 8 个一组,对应于四个象限,准备好打印。
奖励积分
这个答案的其余部分仅仅是为我无耻的奖励积分清理辩护。
来自你的问题:
bonus points for quarter winds!
来自 Liz 的回答:
Leaving the quarter winds as an exercise for the reader
“四分风”的三十二点
正如 Liz 所说,一个简单的超集解决方案包括她的 和 四分之一风只需要:
using the quarter winds as the base, and work off of that in a similar fashion
换句话说,做 quarter winds bonus 练习可能只需要编写简单、易于理解且易于维护的东西,即在 quarter wind 列表中写出 32 点,就像 Liz 为 16 点所做的那样半风。 (但那样我就得不到奖励积分了。)
将其扩展到容易混淆的半分(64 分)和四分之一分(128 分),明智的做法是手写它们,并附上 Unicode 小数字符,任何支持 Unicode 源代码和类似功能(例如 Raku)的“引用词”的 PL 都变得微不足道。我敢肯定,如果您这样做,任何阅读您的代码的人都会感谢您保持代码的简单性。
但我想找点乐子,坚持您的程序化主题,并尝试获得一些“奖励积分”。因此我的代码在一开始。
我将创建 half/quarter 点的更不必要的复杂、神秘、繁琐的计算结构(包括对别名的支持以及世界各地用于这些更精细的圆规的不同约定)作为读者的练习。 .
结束了这个...
my @all-points = <N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW>;
my %pnt-count = %( cardinal => 4, ordinal => 8, half-winds => 16 );
my $iter = %pnt-count{$dec};
my $step = 360 / $iter;
my $rvc = ( $.value + $step/2 ) % 360; #rotate value clockwise by half-step
for 0..^$iter -> $i {
my $port = $step * $i;
my $star = $step * ($i+1);
if $port < $rvc <= $star { #using slice to sample @all-points
return @all-points[0,(16/$iter)...*][$i]
}
}
我尝试从红衣主教风 (NESW
) 开始,但很快发现最好从 abcd
开始,因为关于 8 风罗盘玫瑰(根据维基百科):
-- In Bulgarian, Catalan, Czech, Danish, Dutch, English, Esperanto, French, Galician, German, Greek, Hungarian, Ido, Italian, Japanese
(usually), Macedonian, Norwegian (both Bokmal and Nynorsk), Polish,
Portuguese, Romansch, Russian, Serbian, Croatian, Spanish, Swedish and
Welsh the part meaning north or south precedes the part meaning east
or west.
-- In Chinese, Gaelic and less commonly in Japanese, the part meaning east or west precedes the other.
首先创建一个16点的玫瑰:
my @cardinal = <a b c d>;
my @intercard = ((@cardinal Z @cardinal[1..*-1,0].flat)>>.join); #between cardinal
my @pre_half = ((@cardinal Z @intercard)>>.join).flat;
my @post_half = (@intercard Z @cardinal[1..*-1,0].flat)>>.join;
my @half = ((@cardinal Z @intercard).flat Z ([Z] @pre_half, @post_half).flat).flat;
say @half;
[a aab ab abb b bbc bc bcc c ccd cd cdd d dda da daa]
现在转换为正确的字母 (NESW)。在16风罗盘中,重新排列3个字母的风,末尾有<same>
个字母,将最后一个字母移到第一个,最后将风向重新排序为英文顺序(North/South先于East/West),intercardinal 风放在最后,例如S-SE 不是 SE-S:
@half.=map(*.trans("abcd" => "NESW"));
@half.=map({ S:g/ <((NE|ES|SW|WN)<same>(.))>$ /[=11=]/});
@half.=map(*.subst(:g, "ES","SE"));
@half.=map(*.subst(:g, "WN","NW"));
say @half;
[N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW]
(...分为两步,以防万一@p6steve 想要将他的代码本地化为中文、盖尔语和日语)。
注意:一旦您生成了 16 点(“半风”)罗盘图,就可以简单地找出 8 点(“序数”)罗盘图:
@half[(0..15).grep(not * % 2)].put;
N NE E SE S SW W NW
HTH.
https://en.m.wikipedia.org/wiki/Compass_rose#/media/File%3ABrosen_windrose.svg
我有这个工作:
my %pnt = %( cardinal => <N E S W>,
ordinal => <N NE E SE S SW W NW>,
half-winds => <N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW>,
);
而且我认为可以通过编程方式创建半风数组。
然而,我的可怜尝试似乎更啰嗦:
my @cards = <N E S W>;
my @odds = <NE SE SW NW>;
my @ords = ( @cards Z @odds ).flat;
my @mids = ( ( @cards Z~ @odds ) Z ( @cards.rotate(1) Z~ @odds ) ).flat;
my @halfs = ( @ords Z @mids ).flat;
say @cards; #[N E S W]
say @ords; #[N NE E SE S SW W NW]
say @mids; #[NNE ENE ESE SSE SSW WSW WNW NNW]
say @halfs; #[N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW]
是否有更好/更简洁的选择?
即。 https://en.wikipedia.org/wiki/Points_of_the_compass -- 季风加分!
FWIW,在这种情况下,我会考虑代码的可读性,我认为您的原始代码是您可以获得的最易读的代码。
但是如果你想获得算法,我会使用使用序列的数组切片来处理 @halfs
:
my @halfs = <N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW>;
my @mids = @halfs[1,3...*];
my @ords = @halfs[0,2...*];
my @cards = @halfs[0,4...*];
say @cards; #[N E S W]
say @ords; #[N NE E SE S SW W NW]
say @mids; #[NNE ENE ESE SSE SSW WSW WNW NNW]
say @halfs; #[N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW]
将四分之一风作为 reader 的练习,但基本上这将使用四分之一风作为基础,并以类似的方式进行处理。
假设我们有主风:
my @principals = <N NE E SE S SW W NW>;
然后我们可以按照维基百科的定义:
The name of each half-wind is constructed by combining the names of the principal winds to either side
这意味着我们要采用重叠对的主风,rotor
可以相当巧妙地做到这一点:
say @principals.rotor(2 => -1);
这给了我们:
((N NE) (NE E) (E SE) (SE S) (S SW) (SW W) (W NW))
遗憾的是,它少了一个问题,因为它错过了 (NW, N)
。好的,我们可以再次包含 N
,以牺牲一点美感为代价:
say @principals[*,0].flat.rotor(2 => -1)
给予:
((N NE) (NE E) (E SE) (SE S) (S SW) (SW W) (W NW) (NW N))
如果我们加入他们:
say @principals[*,0].flat.rotor(2 => -1).map(*.join)
我们得到:
(NNE NEE ESE SES SSW SWW WNW NWN)
这还不对,因为文章接下来要说的是:
with the cardinal wind coming first and the intercardinal wind second
基风是一个字符的,可以通过排序来固定:
say @principals[*,0].flat.rotor(2 => -1).map(*.sort(*.chars).join)
最后看起来是对的:
(NNE ENE ESE SSE SSW WSW WNW NNW)
除了半风是放在主风之间的,这可以通过压缩它们并压平结果来解决:
say flat @principals Z @principals[*,0].flat.rotor(2 => -1).map(*.sort(*.chars).join)
最后给我们:
(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW)
如果我们想让它更短,重复提到的 @principals
可以用 given
:
say flat $_ Z .[*,0].flat.rotor(2 => -1).map(*.sort(*.chars).join) given @principals
.join
就可以变成列表字符串化:
say flat $_ Z .[*,0].flat.rotor(2 => -1).map(~*.sort(*.chars)) given @principals:
并且可以使用 |
滑动运算符替换内部展平:
say flat $_ Z (|$_,.[0]).rotor(2 => -1).map(~*.sort(*.chars)) given @principals;
这仍然比首先列出它们要长,这是我可能会做的,但无论如何尝试击败它很有趣...
TL;DR 没有充分的理由,这个答案在只是 奖励积分之后。
my \quadrant = <N NbE NNE NEbN NE NEbE ENE EbN E>;
my @quarts = |quadrant,
|quadrant.reverse.map( *.trans: 'NE'=>'SE'),
|quadrant\ .map( *.trans: 'NE'=>'SW'),
|quadrant.reverse.map( *.trans: 'NE'=>'NW');
@quarts .=unique .batch(8) .map: *.say;
# (N NbE NNE NEbN NE NEbE ENE EbN)
# (E EbS ESE SEbE SE SEbS SSE SbE)
# (S SbW SSW SWbS SW SWbW WSW WbS)
# (W WbN WNW NWbW NW NWbN NNW NbW)
也许我解释了以上内容会得到一些加分:
前缀
|
"slips"其右边的值;在四个象限中的每一个上使用它的净效果是结果列表包含 32 个元素而不是 4 个。.reverse
反转列表,对应于风点符号在 NE/SW 和 SE/NW 之间反转的方式。.map(...)
将函数或 lambda 应用于其调用列表中的每个元素。*.trans: 'NE'=>'SE'
是一个 lambda,它将每个N
字符音译为S
,将每个E
音译为E
。冗余的E
是第一次音译,因为它感觉比删除它更清晰;我也可以为第一象限添加*.trans: 'NE'=>'NE'
,但感觉 less 清楚。注意。我使用trans
是因为它简洁,但是subst
总是可以做trans
做的同样的事情,即使它需要更多的行,并且在 Rakudo 2020.12subst
是几乎所有情况下都快 5 到 10 倍。|quadrant\ .map...
中的\
是一个“非空格”,这是一种向编译器表明它应该像斜杠和空格一样解析代码的方式那里。没有它,|
仅将quadrant
作为其操作数。 unspace 使其将整个quadrant.map( *.trans: 'NE'=>'SW')
表达式作为其操作数。 (在我这个答案的原始版本中,我的代码是错误的,因为我把.map
排成一行,没有空格。).=unique
中的.=
应用一个方法,然后将结果赋值给它的调用者,就地改变它。unique
删除列表中重复的所有元素。没有它就会有四个基点的重复(<N E S W>
)。.batch(8)
将点重新分成 8 个一组,对应于四个象限,准备好打印。
奖励积分
这个答案的其余部分仅仅是为我无耻的奖励积分清理辩护。
来自你的问题:
bonus points for quarter winds!
来自 Liz 的回答:
Leaving the quarter winds as an exercise for the reader
“四分风”的三十二点
正如 Liz 所说,一个简单的超集解决方案包括她的 和 四分之一风只需要:
using the quarter winds as the base, and work off of that in a similar fashion
换句话说,做 quarter winds bonus 练习可能只需要编写简单、易于理解且易于维护的东西,即在 quarter wind 列表中写出 32 点,就像 Liz 为 16 点所做的那样半风。 (但那样我就得不到奖励积分了。)
将其扩展到容易混淆的半分(64 分)和四分之一分(128 分),明智的做法是手写它们,并附上 Unicode 小数字符,任何支持 Unicode 源代码和类似功能(例如 Raku)的“引用词”的 PL 都变得微不足道。我敢肯定,如果您这样做,任何阅读您的代码的人都会感谢您保持代码的简单性。
但我想找点乐子,坚持您的程序化主题,并尝试获得一些“奖励积分”。因此我的代码在一开始。
我将创建 half/quarter 点的更不必要的复杂、神秘、繁琐的计算结构(包括对别名的支持以及世界各地用于这些更精细的圆规的不同约定)作为读者的练习。 .
结束了这个...
my @all-points = <N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW>;
my %pnt-count = %( cardinal => 4, ordinal => 8, half-winds => 16 );
my $iter = %pnt-count{$dec};
my $step = 360 / $iter;
my $rvc = ( $.value + $step/2 ) % 360; #rotate value clockwise by half-step
for 0..^$iter -> $i {
my $port = $step * $i;
my $star = $step * ($i+1);
if $port < $rvc <= $star { #using slice to sample @all-points
return @all-points[0,(16/$iter)...*][$i]
}
}
我尝试从红衣主教风 (NESW
) 开始,但很快发现最好从 abcd
开始,因为关于 8 风罗盘玫瑰(根据维基百科):
-- In Bulgarian, Catalan, Czech, Danish, Dutch, English, Esperanto, French, Galician, German, Greek, Hungarian, Ido, Italian, Japanese (usually), Macedonian, Norwegian (both Bokmal and Nynorsk), Polish, Portuguese, Romansch, Russian, Serbian, Croatian, Spanish, Swedish and Welsh the part meaning north or south precedes the part meaning east or west.
-- In Chinese, Gaelic and less commonly in Japanese, the part meaning east or west precedes the other.
首先创建一个16点的玫瑰:
my @cardinal = <a b c d>;
my @intercard = ((@cardinal Z @cardinal[1..*-1,0].flat)>>.join); #between cardinal
my @pre_half = ((@cardinal Z @intercard)>>.join).flat;
my @post_half = (@intercard Z @cardinal[1..*-1,0].flat)>>.join;
my @half = ((@cardinal Z @intercard).flat Z ([Z] @pre_half, @post_half).flat).flat;
say @half;
[a aab ab abb b bbc bc bcc c ccd cd cdd d dda da daa]
现在转换为正确的字母 (NESW)。在16风罗盘中,重新排列3个字母的风,末尾有<same>
个字母,将最后一个字母移到第一个,最后将风向重新排序为英文顺序(North/South先于East/West),intercardinal 风放在最后,例如S-SE 不是 SE-S:
@half.=map(*.trans("abcd" => "NESW"));
@half.=map({ S:g/ <((NE|ES|SW|WN)<same>(.))>$ /[=11=]/});
@half.=map(*.subst(:g, "ES","SE"));
@half.=map(*.subst(:g, "WN","NW"));
say @half;
[N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW]
(...分为两步,以防万一@p6steve 想要将他的代码本地化为中文、盖尔语和日语)。
注意:一旦您生成了 16 点(“半风”)罗盘图,就可以简单地找出 8 点(“序数”)罗盘图:
@half[(0..15).grep(not * % 2)].put;
N NE E SE S SW W NW
HTH.
https://en.m.wikipedia.org/wiki/Compass_rose#/media/File%3ABrosen_windrose.svg