Developer
Developer

Reputation: 6350

Check hash values before pushing to an array in perl

For creating a Json file i am pushing a hashes in an array but the values are getting duplicated now i don't want to add those hashes which are already in the array.

foreach my $corp_id(@{corpId}) {
    foreach my $rcode(@{$brands_map->{$corp_id->{s_brand}}}) {
            my corpIdAccessCode;
            $corpIdAccessCode->{accessCode} = $corp_id->{s_id};
            $corpIdAccessCode->{corporateId} = $corp_id->{c_id};
            $corpIdAccessCode->{bcode} = $rcode;
            push @{$accessCode_array} ,$corpIdAccessCode; **// Here before pushing to array i want to have a check wheather $corp_id->{s_id}, $corp_id->{c_id} and  $rcode already exists or not in the accessCode_array**
    }
}

So from the below array of hashes i don't want duplicate ones

[
      {
        "accessCode": "NQ",
        "bcode": "PD",
        "corporateId": "12"
      },
      {
        "accessCode": "NQ",
        "bcode": "CI",
        "corporateId": "2122121"
      },
      {
        "accessCode": "NQ",
        "bcode": "CI",
        "corporateId": "2122121"
      },
      {
        "accessCode": "CD",
        "bcode": "PD",
        "corporateId": "12"
      },

The final ooutput from the code changes should give a result like below :

[
      {
        "accessCode": "NQ",
        "bcode": "PD",
        "corporateId": "12"
      },
      {
        "accessCode": "NQ",
        "bcode": "CI",
        "corporateId": "2122121"
      },

      {
        "accessCode": "CD",
        "bcode": "PD",
        "corporateId": "12"
      },

Or is there any way we can remove duplicate hashes from the array.

Upvotes: 0

Views: 66

Answers (2)

ikegami
ikegami

Reputation: 386696

Checking !$seen{$key}++ is a common way of identifying the first of duplicates. For example,

my %seen;
my @uniques = grep { !$seen{$_}++ } @items;

This can be unrolled into a foreach loop.

my %seen;
for my $corp_id (@corpId) {
    for my $rcode (@{ $brands_map->{ $corp_id->{s_brand} } }) {
        next if $seen{ $corp_id->{s_id} }{ $corp_id->{c_id} }{ $rcode }++;

        push @$accessCode_array, {
            accessCode  => $corp_id->{s_id},
            corporateId => $corp_id->{c_id},
            bcode       => $rcode,
        };
    }
}

To save memory, you could even replace

next if $seen{ $corp_id->{s_id} }{ $corp_id->{c_id} }{ $rcode }++;

with

next if $seen{ join ":", $corp_id->{s_id}, $corp_id->{c_id}, $rcode }++;

but that assumes none of the three fields can contain :.

Upvotes: 0

UjinT34
UjinT34

Reputation: 4997

It would be ineficient to check the whole array before pushing or remove duplicates afterwards. So you need to keep track what data you have pushed already:

my $seen;
foreach my $corp_id(@{corpId}) {
    foreach my $rcode(@{$brands_map->{$corp_id->{s_brand}}}) {
            my ($k1, $k2, $k3) = ($corp_id->{s_id}, $corp_id->{c_id}, $rcode);
            if ($seen->{$k1}->{$k2}->{$k3}) {
                next;
            }
            $seen->{$k1}->{$k2}->{$k3} = 1;

            my $corpIdAccessCode;
            $corpIdAccessCode->{accessCode} = $corp_id->{s_id};
            $corpIdAccessCode->{corporateId} = $corp_id->{c_id};
            $corpIdAccessCode->{bcode} = $rcode;
            push @{$accessCode_array} ,$corpIdAccessCode; **// Here before pushing to array i want to have a check wheather $corp_id->{s_id}, $corp_id->{c_id} and  $rcode already exists or not in the accessCode_array**
    }
}

my ($k1, $k2, $k3) just to make it shorter and more readable.

Upvotes: 1

Related Questions