Hash from two arrays: Difference between revisions

From Rosetta Code
Content added Content deleted
(Note about C++ unordered maps)
Line 48: Line 48:


=={{header|C++}}==
=={{header|C++}}==
By strict definition a std::map is not a hash, but it provides the same functionality (but note that some C++ has hash sets too).
By strict definition a std::map is not a hash, but it provides the same functionality. The C++-200x update to the C++ standard is incorporating hashes. When they are standardized the code below can change ''std::map'' to ''std::unordered_map'' and this will technically be a hash table. The core idea, turning two sequences into an associative mapping, is valid either way.


{{works with|g++|4.0.2}}
#include <map>
#include <map>
#include <string>
#include <string>

Revision as of 16:06, 9 May 2008

Task
Hash from two arrays
You are encouraged to solve this task according to the task description, using any language you may know.

Using two Arrays of equal length, create a Hash object where the elements from one array (the keys) are linked to the elements of the other (the values)

Ada

Works with: GNAT version GPL 2007
with Ada.Strings.Hash;
with Ada.Containers.Hashed_Maps;
with Ada.Text_Io;
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;

procedure Hash_Map_Test is
   function Equivalent_Key (Left, Right : Unbounded_String) return Boolean is
   begin
      return Left = Right;
   end Equivalent_Key;
  
   function Hash_Func(Key : Unbounded_String) return Ada.Containers.Hash_Type is
   begin
      return Ada.Strings.Hash(To_String(Key));
   end Hash_Func;
  
   package My_Hash is new Ada.Containers.Hashed_Maps(Key_Type => Unbounded_String,
      Element_Type => Unbounded_String,
      Hash => Hash_Func,
      Equivalent_Keys => Equivalent_Key);
     
   type String_Array is array(Positive range <>) of Unbounded_String;
     
   Hash : My_Hash.Map;
   Key_List : String_Array := (To_Unbounded_String("foo"), 
      To_Unbounded_String("bar"),
      To_Unbounded_String("val"));
     
   Element_List : String_Array := (To_Unbounded_String("little"), 
      To_Unbounded_String("miss"), 
      To_Unbounded_String("muffet"));
     
begin
   for I in Key_List'range loop
      Hash.Insert(Key => (Key_List(I)),
         New_Item => (Element_List(I)));
   end loop;
   for I in Key_List'range loop
      Ada.Text_Io.Put_Line(To_String(Key_List(I)) & " => " &
         To_String(Hash.Element(Key_List(I))));
   end loop;
  
end Hash_Map_Test;

C++

By strict definition a std::map is not a hash, but it provides the same functionality. The C++-200x update to the C++ standard is incorporating hashes. When they are standardized the code below can change std::map to std::unordered_map and this will technically be a hash table. The core idea, turning two sequences into an associative mapping, is valid either way.

#include <map>
#include <string>

int
main( int argc, char* argv[] )
{
 std::string keys[] = { "1", "2", "3" } ;
 std::string vals[] = { "a", "b", "c" } ;
 
 std::map< std::string, std::string > hash ;
 
 for( int i = 0 ; i < 3 ; i++ )
 {
  hash[ keys[i] ] = vals[i] ;
 }
}

Alternatively:

#include <map>       // for std::map
#include <algorithm> // for std::transform
#include <string>    // for std::string
#include <utility>   // for std::make_pair

int main()
{
  std::string keys[] = { "one", "two", "three" };
  std::string vals[] = { "foo", "bar", "baz" };

  std::map<std::string, std::string> hash;

  std::transform(keys, keys+3,
                 vals,
                 std::inserter(hash, hash.end()),
                 std::make_pair<std::string, std::string>);
}

C#

 System.Collections.HashTable h = new System.Collections.HashTable();
 
 string[] arg_keys = {"foo","bar","val"};
 string[] arg_values = {"little", "miss", "muffet"};
   
 //Some basic error checking
 int arg_length = 0;
 if ( arg_keys.Length == arg_values.Length ) {
   arg_length = arg_keys.Length;
 }
 
 for( int i = 0; i < arg_length; i++ ){
   h.add( arg_keys[i], arg_values[i] ); 
 }

Alternate way of adding values

 for( int i = 0; i < arg_length; i++ ){
   h[ arg_keys[i] ] = arg_values[i]; 
 }

D

string[] keys = ["one", "two", "three"]
int[] values  = [1, 2, 3];

int[string] hash;

foreach(idx, key; keys)
  hash[key] = values[idx];

E

def keys := ["one", "two", "three"]
def values := [1, 2, 3]
__makeMap.fromColumns(keys, values)

Groovy

keys = ['a','b','c']
vals = ['aaa', 'bbb', 'ccc']
hash = [:]
i = 0
keys.each { entry ->
 hash.put(entry, vals[i++]) 
}

Haskell

Works with: GHCi version 6.6
import Data.Map

makeMap ks vs = fromList $ zip ks vs
mymap = makeMap ['a','b','c'] [1,2,3]

J

f=: y {~ x&i.

For example:

   x=: 10?.100 
   y=: > ;:'zero one two three four five six seven eight nine'
   f=: y {~ x&i.

   x
46 99 23 62 42 44 12 5 68 63
   $y
10 5

   f 46
zero 
   f 99
one  
   f 63 5 12 5 23
nine 
seven
six  
seven
two

Here, x is a list of 10 integers between 0 and 99 chosen at random without repetition, and y is a 10 by 5 character matrix.

Java

import java.util.HashMap;
public class Hash{
	public static void main(String[] args){
		String[] keys= {"a", "b", "c"};
		int[] vals= {1, 2, 3};
		HashMap<String, Integer> hash= new HashMap<String, Integer>();

		for(int i= 0; i < keys.length; i++){
			hash.put(keys[i], vals[i]);
		}
	}
}

JavaScript

var keys = ['a', 'b', 'c'];
var values = [1, 2, 3];
var map = {};
for(var i in keys) {
  map[ keys[i] ] = values[i];
}

OCaml

The idiomatic solution uses lists rather than arrays.

 let keys = [ "foo"; "bar"; "baz" ]
 and vals = [ 16384; 32768; 65536 ]
 and hash = Hashtbl.create 0;;
 List.iter2 (Hashtbl.add hash) keys vals;;

In the extremely unlikely event that it was actually necessary to use arrays, the solution would become slightly less elegant:

 let keys = [| "foo"; "bar"; "baz" |]
 and vals = [| 16384; 32768; 65536 |]
 and hash = Hashtbl.create 0;;
 for i = 0 to Array.length keys - 1 do
   Hashtbl.add hash keys.(i) vals.(i)
 done;;

In either case, an exception is raised if the inputs are different lengths.

Perl

Works with: Perl version 5
use List::MoreUtils qw(zip);

my @keys = qw(a b c);
my @vals = (1, 2, 3);
my %hash = zip @keys, @vals;

Using no modules:

my %hash;
@hash{qw(a b c)} = (1, 2, 3);

PHP

Works with: PHP version 5
$keys = array('a', 'b', 'c');
$values = array(1, 2, 3);
$hash = array_combine($keys, $values);
Works with: PHP version 4
$keys = array('a', 'b', 'c');
$values = array(1, 2, 3);
$hash = array();
for ($idx = 0; $idx < count($keys); $idx++) {
  $hash[$keys[$idx]] = $values[$idx];
}

Pop11

vars keys = { 1 a b c};
vars vals = { 2 3 valb valc};
vars i;
;;; Create hash table
vars ht = newmapping([], 500, 0, true);
;;; Loop over input arrays (vectors)
for i from 1 to length(keys) do
  vals(i) -> ht(keys(i));
endfor;

Prolog

% this one with side effect hash table creation

:-dynamic hash/2.

make_hash([],[]).
make_hash([H|Q],[H1|Q1]):-
	assert(hash(H,H1)),
	make_hash(Q,Q1).

:-make_hash([un,deux,trois],[[a,b,c],[d,e,f],[g,h,i]])


% this one without side effects 

make_hash_pure([],[],[]).
make_hash_pure([H|Q],[H1|Q1],[hash(H,H1)|R]):-
	make_hash_pure(Q,Q1,R).

:-make_hash_pure([un,deux,trois],[[a,b,c],[d,e,f],[g,h,i]],L),findall(M,(member(M,L),assert(M)),L).

Python

Works with: Python version 2.3+
keys = ['a', 'b', 'c']
values = [1, 2, 3]
hash = dict(zip(keys, values))

# Lazily:
from itertools import izip
hash = dict(izip(keys, values))
Works with: Python

(any version)

keys = ['a', 'b', 'c']
values = [1, 2, 3]
hash = {}
for i range(len(keys)):
    hash[keys[i]] = values[i]

Raven

[ 'a' 'b' 'c' ] as $keys [ 1 2 3 ] as $vals
$keys $vals combine as $hash

Ruby

 keys=['hal',666,[1,2,3]]
 vals=['ibm','devil',123]
 hash = Hash[*keys.zip(vals).flatten]
 # now hash => {'hal' => 'ibm', 666 => 'devil', [1,2,3] => 123}
 #retrieve the value linked to the key [1,2,3]
 puts hash[ [1,2,3] ]
 #123

Scala

val keys = Array(1, 2, 3)
val values = Array("A", "B", "C")
val map = Map(keys.zip(values) : _*)
// returns Map(1 -> "A", 2 -> "B", 3 -> "C")
// keys.zip(values) is an array of pairs : Array((1, "A"), (2, "B"), (3, "C"))
// Map(...) expects multiple pairs arguments. Syntax ": _*" tells the single argument contains multiple values.

Seed7

$ include "seed7_05.s7i";

const type: numericHash is hash [string] integer;
var numericHash: myHash is numericHash.value;

const proc: main is func
  local
    var array string: keyList is [] ("one", "two", "three");
    var array integer: valueList is [] (1, 2, 3);
    var integer: number is 0;
  begin
    for number range 1 to length(keyList) do
      myHash @:= [keyList[number]] valueList[number];
    end for;
  end func;

Tcl

Arrays in Tcl are automatically associative, i.e. there are no "not hashed arrays". If we can take "arrays of equal length" to mean "lists of equal length", then the task might look like this:

set keys [list fred bob joe]
set values [list barber plumber tailor]
array set arr {}
foreach a $keys b $values { set $arr($a) $b }

UnixPipes

Using a sorted file as an associative array (see Creating an associative array for usage.)

cat <<VAL >p.values
apple
boy
cow
dog
elephant
VAL
cat <<KEYS >p.keys
a
b
c
d
e
KEYS
paste -d\   <(cat p.values | sort) <(cat p.keys | sort)