我将大量数据保存为Data :: Dumper输出。
我想在世界上如何阅读这些数据?我想重组它,但我完全迷失了方法。数据结构是散列哈希值的数组中的哈希......
这是一个(非常精简的)示例。此外,创作并不是很好,因为角色可以有两个“攻击”或两个“特殊”,所以很明显它是一个碰撞,一个将被覆盖。
编辑:我真正要问的是:这是存储这类数据的理想方式吗?或者,还有更好的方法?因为对我来说像$char_hash{Character Name}{abilities}{attack}{tiers}{level 1}{description}
那样访问哈希似乎很难写。迭代@{$char_hash{Character Name}{Equipment}{Equipment Level 1}{Items}}
这样的事情似乎很难实现
my @char_hash = (
"Character Name" => {
"description" => "",
"alignment" => "",
"categories" => [
"ex 1",
"ex 2",
"ex 4",
"ex 5"
],
"primaryStat" => "Strength (STR)",
"baseStats" => {
"Strength (STR)" => "22",
"Agility (AGI)" => "15",
"Intelligence (INT)" => "17",
"Speed" => "100",
"Health" => "197",
"Physical Damage" => "17"
},
"abilities" => {
"attack" => {
"name" => "ex 1",
"type" => "Physical",
"tiers" => {
"level 1" => {
"description" => ""
},
"level 2" => {
"unlockLevel" => 16,
"cost" => {
"Money" => 700,
"Material" => 3
},
"fromPrevious" => "+5% Damage",
"description" => ""
}
},
"conditions" => {
}
},
"special" => {
"name" => "ex",
"cooldown" => 3,
"type" => "special",
"tiers" => {
"level 1" => {
"description" => ""
},
"level 2" => {
"unlockLevel" => 18,
"cost" => {
"Money" => 1300,
"Material" => 2
},
"fromPrevious" => "+5% Damage",
"description" => ""
}
},
"conditions" => {
}
},
"Equipment" => {
"Equipment Lvl I" => {
"cummulatedStats" => {
"Strength (STR)" => "+22",
"Agility (AGI)" => "+15",
"Intelligence (INT)" => "+17",
"Speed" => "+100",
"Health" => "+197",
"Physical Damage" => "+17"
},
"items" => [
{
"name" => "",
"id" => "",
"tier" => 1,
"mark" => "",
"requiredLevel" => 1,
"sellValue" => 10,
"stats" => {
"Physical Damage" => ""
}
},
{
"name" => "",
"id" => "",
"tier" => 1,
"mark" => "",
"requiredLevel" => 2,
"sellValue" => 20,
"stats" => {
"Strength (STR)" => "",
"Agility (AGI)" => "",
"Intelligence (INT)" => ""
}
},
{
"name" => "",
"id" => "",
"tier" => 1,
"mark" => "",
"requiredLevel" => 2,
"sellValue" => 20,
"stats" => {
"Strength (STR)" => "",
"Agility (AGI)" => "",
"Intelligence (INT)" => ""
}
},
{
"name" => "",
"id" => "",
"tier" => 1,
"mark" => "",
"requiredLevel" => 2,
"sellValue" => 20,
"stats" => {
"Speed" => ""
}
},
{
"name" => "",
"id" => "",
"tier" => 1,
"mark" => "",
"requiredLevel" => 2,
"sellValue" => 20,
"stats" => {
"Strength (STR)" => ""
}
},
{
"name" => "",
"id" => "",
"tier" => 1,
"mark" => "",
"requiredLevel" => 2,
"sellValue" => 20,
"stats" => {
"Armor" => ""
}
}
]
}
}
}
}
);
答案 0 :(得分:3)
我会说是的,有更好的方法。
答案是 - 使用面向对象的代码。如果你没有真正遇到它,OO可能听起来很恐怖 - 并且有很多Java或C ++程序员喜欢这样做。
但真正的所有内容都是一个包含代码'内置'的数据结构。操纵它。这些代码被称为"方法"并适用于该对象。
所以 - 采取以上措施。你有"字符"和"设备"作为'对象的明显例子。
#!/usr/bin/env perl
package MyStuff::Character;
use strict;
use warnings;
sub new {
my ( $class, $name ) = @_;
my $self = {};
$self -> {name} = $name;
bless $self, $class;
return $self;
}
sub set_attr {
my ( $self, $attr, $value ) = @_;
$self -> {attr} -> {$attr} = $value;
}
sub get_attr {
my ( $self, $attr ) = @_;
return $self -> {attr} -> {$attr};
}
sub get_name {
my ( $self ) = @_;
return $self -> {name};
}
sub add_item {
my ( $self, $item_ref ) = @_;
push ( @{ $self -> {items} }, $item_ref );
}
sub inventory {
my ( $self ) = @_;
return @{$self->{items}};
}
package MyStuff::Items;
sub new {
my ( $class, $name, $type ) = @_;
my $self = {};
$self -> {name} = $name;
$self -> _set_type($type);
bless $self, $class;
return $self;
}
sub get_name {
my ( $self ) = @_;
return $self -> {name};
}
sub _set_type {
my ( $self, $type ) = @_;
$self -> {type} = $type;
if ( $type eq "sword" ) {
$self -> {attack_bonus} = "+10";
}
}
package main;
use strict;
use warnings;
my $character = MyStuff::Character -> new ( "Joe Beefcake" );
$character -> set_attr('STR', 9000);
print $character -> get_name, " has STR ", $character -> get_attr('STR'),"\n";
my $new_sword = MyStuff::Character -> new ( "Hackmaster", "sword");
$character -> add_item( $new_sword );
print "And is carrying:\n";
foreach my $item ( $character -> inventory ) {
print $item -> get_name,"\n";
}
这是一个非常基本的例子,但希望说明一种处理复杂数据结构的新方法?
具体来说 - 我们将其交给'我们不关心的事物,要照顾的对象,只是使用方法与之交互。因为一个项目是一个自包含的对象,它知道'它的状态。你可以拿走它,然后给予'它是另一个角色。
这样做的另一个好处是继承。我有一个非常通用的项目'宾语。每件物品都有你可能想要做的事情 - 拿起它们,携带它们,卖掉它们,然后把它们交给另一个人。
但是你可以制作一把武器' class,继承" item"上课(所以你仍然可以给别人一把剑),但也增加额外的东西 - 比如攻击加成,熟练度要求,攻击加成等等。
面向对象的概念并不是一个新概念,但它在perl中并不常见。那里有perldoc perlobj
,其中有一些基础知识。
还有一些软件包可以帮助完成此过程(上述工作是独立的),例如Moose
。
为"保存"和#34; loading" - 有很多可能的选择,这取决于一点。
我可能通过序列化字符'来解决它和'项目'分别到JSON,并重新加载/验证。
这里详细介绍了这些内容:How to convert Perl objects into JSON and vice versa
答案 1 :(得分:0)
首先,当我将数据发布到文件中并在vi中使用percent命令时,我发现我认为是一个粘贴错误。事实上,'能力' hash有三个条目,包括" Equipment"。看看缩进这看起来像是一个错误 - 我相信在字母上方缺少一个结束的卷曲" E"在"设备"并且需要删除相应的结束卷曲(文件中的第三个最后一个)。然后"设备"成为角色的特征,而不是一种似乎更有可能的能力。
在纠正之后,你能做什么?我认为这不是一个简单的方法 - 您必须梳理数据以寻找重复的模式并识别可以作为对象候选的数据分组。
从顶部开始忽略细节,我们看到一个角色由七个属性组成 - 可能没有它看起来那么糟糕。我将使用perl6作为更简洁的类声明,坦率地说,有了这么大的东西,任何解决方案都是一个很好的解决方案(或者更直接地说,我不想整天都在这里); < / p>
class Character {
has $.description ;
has $.alignment ;
has $.categories ;
has $.primaryStat ;
has $.baseStats ;
has Abilities $.abilities ;
has %.equipment of Equipment ;
}
baseStats
本身可能是一个对象,但它是一个直接的哈希 - 所以留下它。这里的想法是仅在需要时根据结构的深度制作子对象。
看abilities
,只有两个;攻击能力和特殊能力。将它们从包含的哈希中取出会更好 - 它为两个条目创建了另一个级别。它们似乎也具有相同的属性,因此,我们可以创建一个Abilities子对象,并在我们的Character类中包含两个 - 一个用于攻击,一个用于特殊。
看起来层是一个散列,其中键是"level n"
,值是散列数据的散列。它值得商榷但是,它可能值得创建一个代表级别或级别的类。所以,这需要我们三个层次 - 再次,也许不像它最初看起来那么糟糕。
设备看起来类似于层,因为它是一个散列,其中键是关卡,值是数据的散列。该数据是"cummulatedStats"
下的内容的直接哈希,然后是项目列表。
再次,它是一个判断调用,但我会说你需要一个Item子对象。所以我们有;
#!/usr/bin/env perl6
class Tiers {
has $.unlockLevel ;
has $.cost ;
has $.fromPrevious ;
has $.description
}
class Abilities {
has $.name ;
has $.cooldown ;
has $.type ;
has %.tiers of Tiers ;
has $.conditions ;
}
class Items {
has $.name ;
has $.id ;
has $.tier ;
has $.mark ;
has $.requiredLevel ;
has $.sellValue ;
has $.stats ;
}
class Equipment {
has $.cummulatedStats ;
has $.items ;
}
class Character {
has $.description ;
has $.alignment ;
has $.categories ;
has $.primaryStat ;
has $.baseStats ;
has Abilities $.attack_abilities ;
has Abilities $.special_abilities ;
has %.equipment of Equipment ;
}
my %char_hash = hash.new(
"description" => "",
"alignment" => "",
... etc from your data ...
现在,我们需要从其哈希中提取Abilities
来创建子对象。我们还需要对Tiers
和Items
执行相同的操作。这篇文章已经太长了,所以我会切入追逐;
my %equipment = %char_hash<Equipment> :delete ;
my %abilities = %char_hash<abilities> :delete ;
my %special = %abilities<special> ;
my %attack = %abilities<attack> ;
%abilities = ();
for %special<tiers>.kv -> $level, $data_hash {
%special<tiers>{ $level } = Tiers.new: |$data_hash
}
for %attack<tiers>.kv -> $level, $data_hash {
%attack<tiers>{ $level } = Tiers.new: |$data_hash
}
%char_hash<special_abilities> = Abilities.new: |%special ;
%char_hash<attack_abilities> = Abilities.new: |%attack ;
for %equipment.kv -> $level, $data_hash is rw {
my @items;
@items.push: Items.new(|$_) for $data_hash<items>.flat ;
$data_hash<items> = @items ;
%equipment{ $level } = Equipment.new: |$data_hash ;
}
%char_hash<equipment> = %equipment ;
my $char = Character.new( |%char_hash );
say $char.perl;
方法是内在的 - 我们从层级开始,因为它们嵌套在最深处。我们创建了关卡的哈希,然后将它们反馈到%special
和%attack
个哈希值。从中我们可以创建两个Abilities
对象并将它们反馈到主哈希%char_hash
。
与Items
和Equipment
类似,然后我们才能最终准备好创建Character
。加载数据后,您可以创建字符串化方法.Str
,以自定义每种类型对象的表示。为您想要实现的操作和转换创建特殊用途的方法也应该很容易。
......我永远不应该开始这个问题; - )