Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to "map" between 3 values?

I have lots of data like this

type1, type2, type3
aax, ert, ddd
asx, eer, kkk
xkk, fff, lll
xxj, vtt, lle
...

and I would really like to be able to "map" between them, so I can go from

type1 -> type2
type1 -> type3
type2 -> type1
type3 -> type1

Example:

type1_to_type2(aax) should return ert
type1_to_type3(asx) should return kkk
type2_to_type3(fff) should return lll
type3_to_type1(lle) should return xxj

What data structure should be used for the data?

And how would such functions look like?

Update: All data is unique.

like image 757
Sandra Schlichting Avatar asked Mar 11 '11 10:03

Sandra Schlichting


3 Answers

A version that actually implements the 'type1_to_type2' etc... functions.

#!/usr/bin/perl

use strict;
use warnings;

my $data;
while (<DATA>) {
  chomp;
  push @$data, [ split ];
}

sub typeX_to_typeY {
  my ($x, $y, $str) = @_;

  foreach (@$data) {
    if ($_->[$x - 1] eq $str) {
      return $_->[$y - 1];
    }
  }

  return;
}

sub type1_to_type2 { typeX_to_typeY(1, 2, @_) }
sub type1_to_type3 { typeX_to_typeY(1, 3, @_) }
sub type2_to_type1 { typeX_to_typeY(2, 1, @_) }
sub type2_to_type3 { typeX_to_typeY(2, 3, @_) }
sub type3_to_type1 { typeX_to_typeY(3, 1, @_) }
sub type3_to_type2 { typeX_to_typeY(3, 2, @_) }

# tests
use Test::More tests => 4;

is(type1_to_type2('aax'), 'ert');
is(type1_to_type3('asx'), 'kkk');
is(type2_to_type3('fff'), 'lll');
is(type3_to_type1('lle'), 'xxj');

__DATA__
aax ert ddd
asx eer kkk
xkk fff lll
xxj vtt lle
like image 177
Dave Cross Avatar answered Sep 27 '22 22:09

Dave Cross


If all the strings are unique, you can use them as keys in a hash:

my %data = (
    aax => ["aax", "ert", "ddd"],
    ert => ["aax", "ert", "ddd"],
    ddd => ["aax", "ert", "ddd"],
    asx => ["asx", "eer", "kkk"],
    ...
);

sub get_value {
    my ($s, $type) = @_;
    return $data{$s}[$type-1];
}

print get_value("aax", 2); # "ert"
like image 40
Eugene Yarmash Avatar answered Sep 27 '22 22:09

Eugene Yarmash


One approach is to use a database for this sort of thing. Here's an illustration:

use strict;
use warnings;

use DBI;
my $dbh = DBI->connect("dbi:SQLite:dbname=demo_db","","");

# Initialize an SQLite DB with some content.
my @init_db = (
    'CREATE TABLE demo (ty1 VARCHAR(5), ty2 VARCHAR(5), ty3 VARCHAR(5));',
    'INSERT INTO demo (ty1, ty2, ty3) values ("aax", "ert", "ddd");',
    'INSERT INTO demo (ty1, ty2, ty3) values ("asx", "eer", "kkk");',
    'INSERT INTO demo (ty1, ty2, ty3) values ("xkk", "fff", "lll");',
    'INSERT INTO demo (ty1, ty2, ty3) values ("xxj", "vtt", "lle");',
);

for my $s (@init_db){
    $dbh->do($s) or die $!;
}

# Query the data by any field we like.
my $sth = $dbh->prepare('SELECT * FROM demo');
$sth->execute();
my $result = $sth->fetchall_hashref('ty1');

The result is a reference to a hash of hashes, keyed by the value of ty1 and then by the field names in our table. For example:

$result->{xkk} = {
  'ty2' => 'fff',
  'ty3' => 'lll',
  'ty1' => 'xkk'
};

If you're interested in just one particular value of a given field, you can use a more specific query. With this approach it's very easy to write utility methods -- for example, take a field name and a value of interest, and return the results in whatever format is most handy.

like image 35
FMc Avatar answered Sep 27 '22 22:09

FMc