如何按行对数据框中的元素进行分组
How to group elements in dataframe by row
我有 this code 本质上是将图像的像素转换为 minecraft 中的一个方块,它为您提供了一个“地图”,说明该方块的放置位置,以便在游戏中形成图像:代码生成一个 csv 文件,其中电子表格中的每个单元格对应一个块。
我想改进这一点,不仅输出 csv 文件,还输出一个 txt 文件,其中包含将在游戏中生成图像的 minecraft 命令。
此外,这些命令必须与玩家的 (x, y, z) 有相对位置,这应该通过元组或其他方式在代码中告知。
因此,假设玩家在游戏中位于 0, 0, 0,并且我的 csv 看起来像
这是用于测试的字典形式的相同数据框
{0: {0: 'minecraft:diorite', 1: 'minecraft:diorite', 2: 'minecraft:stone'},
1: {0: 'minecraft:stone', 1: 'minecraft:stone', 2: 'minecraft:cobblestone'},
2: {0: 'minecraft:block_of_raw_iron',
1: 'minecraft:diamond_block',
2: 'minecraft:gold_block'}}
我希望我的 txt 输出是
/fill 0 0 0 0 0 1 minecraft:diorite
/fill 0 0 2 0 0 2 minecraft:stone
/fill 1 0 0 1 0 1 minecraft:stone
/fill 1 0 2 1 0 2 minecraft:cobblestone
/fill 2 0 0 2 0 0 minecraft:block_of_raw_iron
/fill 2 0 1 2 0 1 minecraft:diamond_block
/fill 2 0 2 2 0 2 minecraft:gold_block
对于那些不知道 minecraft 命令语法的人:
/fill {x_start} {y_start} {z_start} {x_end} {y_end} {z_end} {block}
[开始,结束](均包括在内),x 横向移动,z 向上或向下移动。
我几乎尝试了所有方法,但我几乎放弃了这段代码,所以我删除了我的进度,抱歉:(
有人可以帮忙吗?提前致谢。
编辑 1.:为了更好地测试,这里是火影忍者的像素艺术(前 5 行)
{0: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 1: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 2: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 3: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 4: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 5: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 6: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 7: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 8: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 9: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 10: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 11: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 12: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 13: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 14: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:block_of_raw_iron'}, 15: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:sand'}, 16: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 17: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 18: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 19: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:sand', 4: 'minecraft:sand'}, 20: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:sand', 3: 'minecraft:block_of_gold', 4: 'minecraft:sponge'}, 21: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:snow_block', 3: 'minecraft:diorite_slab', 4: 'minecraft:sand'}, 22: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:snow_block', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 23: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:snow_block', 3: 'minecraft:snow_block', 4: 'minecraft:diorite_slab'}, 24: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:snow_block', 3: 'minecraft:sand', 4: 'minecraft:block_of_gold'}, 25: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:sand', 3: 'minecraft:sponge', 4: 'minecraft:sponge'}, 26: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:sand', 4: 'minecraft:white_terracotta'}, 27: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 28: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:diorite_slab'}, 29: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:sand'}, 30: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:sand', 4: 'minecraft:sponge'}, 31: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 32: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:snow_block'}, 33: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 34: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 35: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 36: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 37: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 38: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 39: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 40: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 41: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 42: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 43: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 44: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 45: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}}
和(我认为是)前 3 列的预期输出(再次假设玩家的位置 0、0、0)。
/fill 0 0 0 0 0 45 minecraft:diorite_slab
/fill 1 0 0 1 0 45 minecraft:diorite_slab
/fill 2 0 0 2 0 26 minecraft:diorite_slab
/fill 2 0 27 2 0 29 minecraft:mushroom_stem
/fill 2 0 30 2 0 45 minecraft:diorite_slab
我尝试基于 un-pivoting 将值矩阵写入坐标表示来编写解决方案,但压缩代码最终变得非常复杂,所以我放弃了它,并编写了一个基于而是嵌套循环,最终更容易编写。
基本上,这会循环遍历行,并且在每一行中,它将相同 material 的块分组,只要这些块是连续的。 (这就是 itertools.groupby() 的目的,它与 Pandas groupby 不同,因为 Pandas 版本 将 分组不连续的值一样。)
import pandas as pd
import itertools
from collections import namedtuple
FillCommand = namedtuple('FillCommand', 'minx minz maxx maxz blocks material')
def compress_row(j, s):
i = 0
for material, group in itertools.groupby(s):
num_elements = len(list(group))
maxz = i + num_elements - 1
yield FillCommand(
minx=j,
minz=i,
maxx=j,
maxz=maxz,
blocks=num_elements,
material=material,
)
i += num_elements
def compress_all(df):
height = len(df.index)
for j in range(height):
yield from compress_row(j, df.iloc[j])
def fill_to_string(fill_commands):
for cmd in fill_commands:
yield f"/fill {cmd.minx} 0 {cmd.minz} {cmd.maxx} 0 {cmd.maxz} {cmd.material}"
def convert_pic_to_fill(df):
return list(fill_to_string(compress_all(df)))
convert_pic_to_fill(df_naruto)
这是这段代码的输出:
/fill 0 0 0 0 0 45 minecraft:diorite_slab
/fill 1 0 0 1 0 45 minecraft:diorite_slab
/fill 2 0 0 2 0 19 minecraft:diorite_slab
/fill 2 0 20 2 0 20 minecraft:sand
/fill 2 0 21 2 0 24 minecraft:snow_block
/fill 2 0 25 2 0 25 minecraft:sand
/fill 2 0 26 2 0 45 minecraft:diorite_slab
/fill 3 0 0 3 0 15 minecraft:diorite_slab
/fill 3 0 16 3 0 18 minecraft:snow_block
/fill 3 0 19 3 0 19 minecraft:sand
/fill 3 0 20 3 0 20 minecraft:block_of_gold
/fill 3 0 21 3 0 21 minecraft:diorite_slab
/fill 3 0 22 3 0 23 minecraft:snow_block
/fill 3 0 24 3 0 24 minecraft:sand
/fill 3 0 25 3 0 25 minecraft:sponge
/fill 3 0 26 3 0 26 minecraft:sand
/fill 3 0 27 3 0 29 minecraft:snow_block
/fill 3 0 30 3 0 30 minecraft:sand
/fill 3 0 31 3 0 45 minecraft:diorite_slab
/fill 4 0 0 4 0 13 minecraft:diorite_slab
/fill 4 0 14 4 0 14 minecraft:block_of_raw_iron
/fill 4 0 15 4 0 15 minecraft:sand
/fill 4 0 16 4 0 18 minecraft:snow_block
/fill 4 0 19 4 0 19 minecraft:sand
/fill 4 0 20 4 0 20 minecraft:sponge
/fill 4 0 21 4 0 21 minecraft:sand
/fill 4 0 22 4 0 22 minecraft:snow_block
/fill 4 0 23 4 0 23 minecraft:diorite_slab
/fill 4 0 24 4 0 24 minecraft:block_of_gold
/fill 4 0 25 4 0 25 minecraft:sponge
/fill 4 0 26 4 0 26 minecraft:white_terracotta
/fill 4 0 27 4 0 27 minecraft:snow_block
/fill 4 0 28 4 0 28 minecraft:diorite_slab
/fill 4 0 29 4 0 29 minecraft:sand
/fill 4 0 30 4 0 30 minecraft:sponge
/fill 4 0 31 4 0 31 minecraft:diorite_slab
/fill 4 0 32 4 0 32 minecraft:snow_block
/fill 4 0 33 4 0 45 minecraft:diorite_slab
这是一个主要使用 shift
和 groupby
的解决方案:
def script(df):
z = (df != df.shift()).cumsum()
zri = z.reset_index()
ix_name = z.index.name
co_name = z.columns.name
for i in z:
v = zri.groupby(i)[ix_name].agg(['first', 'last'])
s = {co_name:i}
e = {co_name:i}
for _, r in v.iterrows():
s[ix_name] = r['first']
e[ix_name] = r['last']
material = df.loc[r['first'], i]
yield f'/fill {s["x"]} 0 {s["z"]} {e["x"]} 0 {e["z"]} {material}'
使用方法:
# df is the DataFrame of your dict
# label the axes
df = df.rename_axis(index='z', columns='x')
# select which axis to make major
a = list(script(df))
b = list(script(df.T))
res = min([a, b], key=len)
关于您的第一个示例数据:
>>> res
['/fill 0 0 0 0 0 1 minecraft:diorite',
'/fill 0 0 2 0 0 2 minecraft:stone',
'/fill 1 0 0 1 0 1 minecraft:stone',
'/fill 1 0 2 1 0 2 minecraft:cobblestone',
'/fill 2 0 0 2 0 0 minecraft:block_of_raw_iron',
'/fill 2 0 1 2 0 1 minecraft:diamond_block',
'/fill 2 0 2 2 0 2 minecraft:gold_block']
在您为“火影忍者的像素艺术”提供的前 5 行中:
>>> res
['/fill 0 0 0 45 0 0 minecraft:diorite_slab',
'/fill 0 0 1 45 0 1 minecraft:diorite_slab',
'/fill 0 0 2 19 0 2 minecraft:diorite_slab',
'/fill 20 0 2 20 0 2 minecraft:sand',
'/fill 21 0 2 24 0 2 minecraft:snow_block',
'/fill 25 0 2 25 0 2 minecraft:sand',
'/fill 26 0 2 45 0 2 minecraft:diorite_slab',
'/fill 0 0 3 15 0 3 minecraft:diorite_slab',
'/fill 16 0 3 18 0 3 minecraft:snow_block',
'/fill 19 0 3 19 0 3 minecraft:sand',
'/fill 20 0 3 20 0 3 minecraft:block_of_gold',
'/fill 21 0 3 21 0 3 minecraft:diorite_slab',
'/fill 22 0 3 23 0 3 minecraft:snow_block',
'/fill 24 0 3 24 0 3 minecraft:sand',
'/fill 25 0 3 25 0 3 minecraft:sponge',
'/fill 26 0 3 26 0 3 minecraft:sand',
'/fill 27 0 3 29 0 3 minecraft:snow_block',
'/fill 30 0 3 30 0 3 minecraft:sand',
'/fill 31 0 3 45 0 3 minecraft:diorite_slab',
'/fill 0 0 4 13 0 4 minecraft:diorite_slab',
'/fill 14 0 4 14 0 4 minecraft:block_of_raw_iron',
'/fill 15 0 4 15 0 4 minecraft:sand',
'/fill 16 0 4 18 0 4 minecraft:snow_block',
'/fill 19 0 4 19 0 4 minecraft:sand',
'/fill 20 0 4 20 0 4 minecraft:sponge',
'/fill 21 0 4 21 0 4 minecraft:sand',
'/fill 22 0 4 22 0 4 minecraft:snow_block',
'/fill 23 0 4 23 0 4 minecraft:diorite_slab',
'/fill 24 0 4 24 0 4 minecraft:block_of_gold',
'/fill 25 0 4 25 0 4 minecraft:sponge',
'/fill 26 0 4 26 0 4 minecraft:white_terracotta',
'/fill 27 0 4 27 0 4 minecraft:snow_block',
'/fill 28 0 4 28 0 4 minecraft:diorite_slab',
'/fill 29 0 4 29 0 4 minecraft:sand',
'/fill 30 0 4 30 0 4 minecraft:sponge',
'/fill 31 0 4 31 0 4 minecraft:diorite_slab',
'/fill 32 0 4 32 0 4 minecraft:snow_block',
'/fill 33 0 4 45 0 4 minecraft:diorite_slab']
附录: 使脚本相对于当前位置。
import numpy as np
def script(df, at=(0,0,0)):
z = (df != df.shift()).cumsum()
zri = z.reset_index()
ix_name = z.index.name
co_name = z.columns.name
for i in z:
v = zri.groupby(i)[ix_name].agg(['first', 'last'])
s = {co_name:i}
e = {co_name:i}
for _, r in v.iterrows():
s[ix_name] = r['first']
e[ix_name] = r['last']
material = df.loc[r['first'], i]
sp = np.array((s['x'], 0, s['z'])) + at
ep = np.array((e['x'], 0, e['z'])) + at
line = ' '.join(tuple(sp.astype(str)) + tuple(ep.astype(str)) + (material, ))
yield f'/fill {line}'
示例:
pos = (-5, 7, 3)
a = list(script(df, at=pos))
b = list(script(df.T, at=pos))
res = min([a, b], key=len)
>>> res
['/fill -5 7 3 -5 7 4 minecraft:diorite',
'/fill -5 7 5 -5 7 5 minecraft:stone',
'/fill -4 7 3 -4 7 4 minecraft:stone',
'/fill -4 7 5 -4 7 5 minecraft:cobblestone',
'/fill -3 7 3 -3 7 3 minecraft:block_of_raw_iron',
'/fill -3 7 4 -3 7 4 minecraft:diamond_block',
'/fill -3 7 5 -3 7 5 minecraft:gold_block']
我有 this code 本质上是将图像的像素转换为 minecraft 中的一个方块,它为您提供了一个“地图”,说明该方块的放置位置,以便在游戏中形成图像:代码生成一个 csv 文件,其中电子表格中的每个单元格对应一个块。
我想改进这一点,不仅输出 csv 文件,还输出一个 txt 文件,其中包含将在游戏中生成图像的 minecraft 命令。
此外,这些命令必须与玩家的 (x, y, z) 有相对位置,这应该通过元组或其他方式在代码中告知。
因此,假设玩家在游戏中位于 0, 0, 0,并且我的 csv 看起来像
这是用于测试的字典形式的相同数据框
{0: {0: 'minecraft:diorite', 1: 'minecraft:diorite', 2: 'minecraft:stone'},
1: {0: 'minecraft:stone', 1: 'minecraft:stone', 2: 'minecraft:cobblestone'},
2: {0: 'minecraft:block_of_raw_iron',
1: 'minecraft:diamond_block',
2: 'minecraft:gold_block'}}
我希望我的 txt 输出是
/fill 0 0 0 0 0 1 minecraft:diorite
/fill 0 0 2 0 0 2 minecraft:stone
/fill 1 0 0 1 0 1 minecraft:stone
/fill 1 0 2 1 0 2 minecraft:cobblestone
/fill 2 0 0 2 0 0 minecraft:block_of_raw_iron
/fill 2 0 1 2 0 1 minecraft:diamond_block
/fill 2 0 2 2 0 2 minecraft:gold_block
对于那些不知道 minecraft 命令语法的人:
/fill {x_start} {y_start} {z_start} {x_end} {y_end} {z_end} {block}
[开始,结束](均包括在内),x 横向移动,z 向上或向下移动。
我几乎尝试了所有方法,但我几乎放弃了这段代码,所以我删除了我的进度,抱歉:(
有人可以帮忙吗?提前致谢。
编辑 1.:为了更好地测试,这里是火影忍者的像素艺术(前 5 行)
{0: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 1: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 2: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 3: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 4: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 5: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 6: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 7: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 8: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 9: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 10: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 11: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 12: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 13: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 14: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:block_of_raw_iron'}, 15: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:sand'}, 16: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 17: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 18: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 19: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:sand', 4: 'minecraft:sand'}, 20: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:sand', 3: 'minecraft:block_of_gold', 4: 'minecraft:sponge'}, 21: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:snow_block', 3: 'minecraft:diorite_slab', 4: 'minecraft:sand'}, 22: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:snow_block', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 23: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:snow_block', 3: 'minecraft:snow_block', 4: 'minecraft:diorite_slab'}, 24: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:snow_block', 3: 'minecraft:sand', 4: 'minecraft:block_of_gold'}, 25: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:sand', 3: 'minecraft:sponge', 4: 'minecraft:sponge'}, 26: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:sand', 4: 'minecraft:white_terracotta'}, 27: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:snow_block'}, 28: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:diorite_slab'}, 29: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:snow_block', 4: 'minecraft:sand'}, 30: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:sand', 4: 'minecraft:sponge'}, 31: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 32: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:snow_block'}, 33: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 34: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 35: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 36: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 37: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 38: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 39: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 40: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 41: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 42: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 43: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 44: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}, 45: {0: 'minecraft:diorite_slab', 1: 'minecraft:diorite_slab', 2: 'minecraft:diorite_slab', 3: 'minecraft:diorite_slab', 4: 'minecraft:diorite_slab'}}
和(我认为是)前 3 列的预期输出(再次假设玩家的位置 0、0、0)。
/fill 0 0 0 0 0 45 minecraft:diorite_slab
/fill 1 0 0 1 0 45 minecraft:diorite_slab
/fill 2 0 0 2 0 26 minecraft:diorite_slab
/fill 2 0 27 2 0 29 minecraft:mushroom_stem
/fill 2 0 30 2 0 45 minecraft:diorite_slab
我尝试基于 un-pivoting 将值矩阵写入坐标表示来编写解决方案,但压缩代码最终变得非常复杂,所以我放弃了它,并编写了一个基于而是嵌套循环,最终更容易编写。
基本上,这会循环遍历行,并且在每一行中,它将相同 material 的块分组,只要这些块是连续的。 (这就是 itertools.groupby() 的目的,它与 Pandas groupby 不同,因为 Pandas 版本 将 分组不连续的值一样。)
import pandas as pd
import itertools
from collections import namedtuple
FillCommand = namedtuple('FillCommand', 'minx minz maxx maxz blocks material')
def compress_row(j, s):
i = 0
for material, group in itertools.groupby(s):
num_elements = len(list(group))
maxz = i + num_elements - 1
yield FillCommand(
minx=j,
minz=i,
maxx=j,
maxz=maxz,
blocks=num_elements,
material=material,
)
i += num_elements
def compress_all(df):
height = len(df.index)
for j in range(height):
yield from compress_row(j, df.iloc[j])
def fill_to_string(fill_commands):
for cmd in fill_commands:
yield f"/fill {cmd.minx} 0 {cmd.minz} {cmd.maxx} 0 {cmd.maxz} {cmd.material}"
def convert_pic_to_fill(df):
return list(fill_to_string(compress_all(df)))
convert_pic_to_fill(df_naruto)
这是这段代码的输出:
/fill 0 0 0 0 0 45 minecraft:diorite_slab
/fill 1 0 0 1 0 45 minecraft:diorite_slab
/fill 2 0 0 2 0 19 minecraft:diorite_slab
/fill 2 0 20 2 0 20 minecraft:sand
/fill 2 0 21 2 0 24 minecraft:snow_block
/fill 2 0 25 2 0 25 minecraft:sand
/fill 2 0 26 2 0 45 minecraft:diorite_slab
/fill 3 0 0 3 0 15 minecraft:diorite_slab
/fill 3 0 16 3 0 18 minecraft:snow_block
/fill 3 0 19 3 0 19 minecraft:sand
/fill 3 0 20 3 0 20 minecraft:block_of_gold
/fill 3 0 21 3 0 21 minecraft:diorite_slab
/fill 3 0 22 3 0 23 minecraft:snow_block
/fill 3 0 24 3 0 24 minecraft:sand
/fill 3 0 25 3 0 25 minecraft:sponge
/fill 3 0 26 3 0 26 minecraft:sand
/fill 3 0 27 3 0 29 minecraft:snow_block
/fill 3 0 30 3 0 30 minecraft:sand
/fill 3 0 31 3 0 45 minecraft:diorite_slab
/fill 4 0 0 4 0 13 minecraft:diorite_slab
/fill 4 0 14 4 0 14 minecraft:block_of_raw_iron
/fill 4 0 15 4 0 15 minecraft:sand
/fill 4 0 16 4 0 18 minecraft:snow_block
/fill 4 0 19 4 0 19 minecraft:sand
/fill 4 0 20 4 0 20 minecraft:sponge
/fill 4 0 21 4 0 21 minecraft:sand
/fill 4 0 22 4 0 22 minecraft:snow_block
/fill 4 0 23 4 0 23 minecraft:diorite_slab
/fill 4 0 24 4 0 24 minecraft:block_of_gold
/fill 4 0 25 4 0 25 minecraft:sponge
/fill 4 0 26 4 0 26 minecraft:white_terracotta
/fill 4 0 27 4 0 27 minecraft:snow_block
/fill 4 0 28 4 0 28 minecraft:diorite_slab
/fill 4 0 29 4 0 29 minecraft:sand
/fill 4 0 30 4 0 30 minecraft:sponge
/fill 4 0 31 4 0 31 minecraft:diorite_slab
/fill 4 0 32 4 0 32 minecraft:snow_block
/fill 4 0 33 4 0 45 minecraft:diorite_slab
这是一个主要使用 shift
和 groupby
的解决方案:
def script(df):
z = (df != df.shift()).cumsum()
zri = z.reset_index()
ix_name = z.index.name
co_name = z.columns.name
for i in z:
v = zri.groupby(i)[ix_name].agg(['first', 'last'])
s = {co_name:i}
e = {co_name:i}
for _, r in v.iterrows():
s[ix_name] = r['first']
e[ix_name] = r['last']
material = df.loc[r['first'], i]
yield f'/fill {s["x"]} 0 {s["z"]} {e["x"]} 0 {e["z"]} {material}'
使用方法:
# df is the DataFrame of your dict
# label the axes
df = df.rename_axis(index='z', columns='x')
# select which axis to make major
a = list(script(df))
b = list(script(df.T))
res = min([a, b], key=len)
关于您的第一个示例数据:
>>> res
['/fill 0 0 0 0 0 1 minecraft:diorite',
'/fill 0 0 2 0 0 2 minecraft:stone',
'/fill 1 0 0 1 0 1 minecraft:stone',
'/fill 1 0 2 1 0 2 minecraft:cobblestone',
'/fill 2 0 0 2 0 0 minecraft:block_of_raw_iron',
'/fill 2 0 1 2 0 1 minecraft:diamond_block',
'/fill 2 0 2 2 0 2 minecraft:gold_block']
在您为“火影忍者的像素艺术”提供的前 5 行中:
>>> res
['/fill 0 0 0 45 0 0 minecraft:diorite_slab',
'/fill 0 0 1 45 0 1 minecraft:diorite_slab',
'/fill 0 0 2 19 0 2 minecraft:diorite_slab',
'/fill 20 0 2 20 0 2 minecraft:sand',
'/fill 21 0 2 24 0 2 minecraft:snow_block',
'/fill 25 0 2 25 0 2 minecraft:sand',
'/fill 26 0 2 45 0 2 minecraft:diorite_slab',
'/fill 0 0 3 15 0 3 minecraft:diorite_slab',
'/fill 16 0 3 18 0 3 minecraft:snow_block',
'/fill 19 0 3 19 0 3 minecraft:sand',
'/fill 20 0 3 20 0 3 minecraft:block_of_gold',
'/fill 21 0 3 21 0 3 minecraft:diorite_slab',
'/fill 22 0 3 23 0 3 minecraft:snow_block',
'/fill 24 0 3 24 0 3 minecraft:sand',
'/fill 25 0 3 25 0 3 minecraft:sponge',
'/fill 26 0 3 26 0 3 minecraft:sand',
'/fill 27 0 3 29 0 3 minecraft:snow_block',
'/fill 30 0 3 30 0 3 minecraft:sand',
'/fill 31 0 3 45 0 3 minecraft:diorite_slab',
'/fill 0 0 4 13 0 4 minecraft:diorite_slab',
'/fill 14 0 4 14 0 4 minecraft:block_of_raw_iron',
'/fill 15 0 4 15 0 4 minecraft:sand',
'/fill 16 0 4 18 0 4 minecraft:snow_block',
'/fill 19 0 4 19 0 4 minecraft:sand',
'/fill 20 0 4 20 0 4 minecraft:sponge',
'/fill 21 0 4 21 0 4 minecraft:sand',
'/fill 22 0 4 22 0 4 minecraft:snow_block',
'/fill 23 0 4 23 0 4 minecraft:diorite_slab',
'/fill 24 0 4 24 0 4 minecraft:block_of_gold',
'/fill 25 0 4 25 0 4 minecraft:sponge',
'/fill 26 0 4 26 0 4 minecraft:white_terracotta',
'/fill 27 0 4 27 0 4 minecraft:snow_block',
'/fill 28 0 4 28 0 4 minecraft:diorite_slab',
'/fill 29 0 4 29 0 4 minecraft:sand',
'/fill 30 0 4 30 0 4 minecraft:sponge',
'/fill 31 0 4 31 0 4 minecraft:diorite_slab',
'/fill 32 0 4 32 0 4 minecraft:snow_block',
'/fill 33 0 4 45 0 4 minecraft:diorite_slab']
附录: 使脚本相对于当前位置。
import numpy as np
def script(df, at=(0,0,0)):
z = (df != df.shift()).cumsum()
zri = z.reset_index()
ix_name = z.index.name
co_name = z.columns.name
for i in z:
v = zri.groupby(i)[ix_name].agg(['first', 'last'])
s = {co_name:i}
e = {co_name:i}
for _, r in v.iterrows():
s[ix_name] = r['first']
e[ix_name] = r['last']
material = df.loc[r['first'], i]
sp = np.array((s['x'], 0, s['z'])) + at
ep = np.array((e['x'], 0, e['z'])) + at
line = ' '.join(tuple(sp.astype(str)) + tuple(ep.astype(str)) + (material, ))
yield f'/fill {line}'
示例:
pos = (-5, 7, 3)
a = list(script(df, at=pos))
b = list(script(df.T, at=pos))
res = min([a, b], key=len)
>>> res
['/fill -5 7 3 -5 7 4 minecraft:diorite',
'/fill -5 7 5 -5 7 5 minecraft:stone',
'/fill -4 7 3 -4 7 4 minecraft:stone',
'/fill -4 7 5 -4 7 5 minecraft:cobblestone',
'/fill -3 7 3 -3 7 3 minecraft:block_of_raw_iron',
'/fill -3 7 4 -3 7 4 minecraft:diamond_block',
'/fill -3 7 5 -3 7 5 minecraft:gold_block']