【问题标题】:How do you Organize / Read a large amount of data? [closed]您如何组织/读取大量数据? [关闭]
【发布时间】:2016-05-25 20:15:30
【问题描述】:

我有大量数据保存为 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" => ""
                            }
                        }
                    ]
                }
            }
        }
}
);

【问题讨论】:

  • 问题是什么?就目前而言,这篇文章太宽泛,没有用处。
  • 我编辑了原帖
  • 您的编辑几乎使问题变得更糟,因为现在任何答案都是意见而不是事实。
  • 没关系。我会听取意见的。现在组织和访问数据似乎令人生畏。你会怎么做?
  • 不,我想你不明白。主要基于意见的问题不被视为on-topic for Stack Overflow,可能会被关闭。

标签: perl data-structures


【解决方案1】:

我会说是的,有更好的方法。

答案是 - 使用面向对象的代码。如果您还没有真正遇到过 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";
}

这是一个非常基本的示例,但希望说明一种处理复杂数据结构的新方法?

具体来说——我们将我们不关心的事情“移交”给要照顾的对象,并使用方法与之交互。因为一个项目是一个自包含的对象,它“知道”它的状态。你可以把它拿走,然后“给”另一个角色。

这样做的另一个好处是继承。我有一个非常通用的“项目”对象。每件物品都包含您可能想对其中任何一件做的事情 - 捡起、携带、出售、送给他人。

但是你可以创建一个“武器”类,它继承了“物品”类(所以你仍然可以给别人你的剑),但也增加了额外的东西——比如攻击加值、熟练度要求、攻击加成等

面向对象的概念并不是一个新概念,但它在 perl 中并不常见。有一个perldoc perlobj,其中包含一些基础知识。

还有一些包可以帮助这个过程(以上独立工作),如Moose

对于“保存”和“加载” - 有许多可能的选项,这取决于一点。

我会可能通过将“字符”和“项目”分别序列化为 JSON 并重新加载/验证来解决它。

这里有更详细的介绍:How to convert Perl objects into JSON and vice versa

【讨论】:

  • 不错的方法!请原谅我的无知,请问您在代码中的哪个位置将数据结构保存到游戏之间的磁盘?
  • 感谢您的帮助,我什至没有考虑 OO 方法。现在想想,继承真的很好。
  • 我没有。以上只是一个说明,实际上它本身就是一个相当广泛的主题。我可能会通过save 方法执行此操作并序列化为JSON。 (例如,保存一个字符,并将“项目”作为单独的文件保存到另一个子目录 - 您将“读入”)
  • 好的,非常感谢您抽出宝贵时间回复。
【解决方案2】:

首先,当我将您的数据发布到文件中并在 vi 中使用百分比命令时,我发现我认为是粘贴错误。事实上,“能力”哈希包含三个条目,包括“设备”。从缩进来看,这看起来很像一个错误——我相信“设备”中字母“E”上方缺少一个结束卷曲,并且需要删除相应的结束卷曲(文件中倒数第三个)。那么“装备”就变成了角色的一个特征,而不是一种看起来更有可能的能力。

改正后,你能做什么?我认为没有简单的出路 - 您必须梳理数据以寻找重复的模式并识别可以作为对象候选的数据分组。

从顶部开始,暂时忽略细节,我们看到一个角色由七个属性组成 - 可能不像最初看起来那么糟糕。我将使用 perl6 作为其更简洁的类声明,坦率地说,有这么大的东西,任何解决方案都是一个很好的解决方案(或者更直接地说,我不想整天待在这里);

class Character {
  has $.description ;
  has $.alignment ;
  has $.categories ;
  has $.primaryStat ;
  has $.baseStats ;
  has Abilities $.abilities ;
  has %.equipment of Equipment ;
}

baseStats 本身可能是一个对象,但它是一个直截了当的散列 - 所以离开它。这里的想法是仅在我们需要时才制作子对象,因为结构的深度。

abilities,只有两个;攻击能力和特殊能力。最好将它们从包含的哈希中取出 - 它为了两个条目而创建另一个级别。它们似乎也具有相同的属性,因此,我们可以创建一个 Abilities 子对象并在我们的 Character 类中包含其中两个 - 一个用于攻击,一个用于特殊。

看起来 tiers 是一个散列,其中键是 "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 从其哈希中提取出来以创建子对象。我们还需要对TiersItems 执行相同的操作。这篇文章已经太长了,所以我会切入正题;

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

在我们最终准备好创建Character 之前,与ItemsEquipment 类似。加载数据后,您可以创建字符串化方法.Str,以自定义每种类型对象的表示。为您想要实现的操作和转换创建特殊用途的方法也应该很容易。

...我不应该从这个问题开始 ;-)

【讨论】:

    猜你喜欢
    • 2010-10-27
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 1970-01-01
    相关资源
    最近更新 更多