Ассоциативный массив

Поделись знанием:
Перейти к: навигация, поиск

Ассоциативный массив — абстрактный тип данных (интерфейс к хранилищу данных), позволяющий хранить пары вида «(ключ, значение)» и поддерживающий операции добавления пары, а также поиска и удаления пары по ключу:

  • INSERT(ключ, значение)
  • FIND(ключ)
  • REMOVE(ключ)

Предполагается, что ассоциативный массив не может хранить две пары с одинаковыми ключами.

В паре <math>(k, v)</math> значение <math>v</math> называется значением, ассоциированным с ключом <math>k</math>. Семантика и названия вышеупомянутых операций в разных реализациях ассоциативного массива могут отличаться.

Операция FIND(ключ) возвращает значение, ассоциированное с заданным ключом, или некоторый специальный объект UNDEF, означающий, что значения, ассоциированного с заданным ключом, нет. Две другие операции ничего не возвращают (за исключением, возможно, информации о том, успешно ли была выполнена данная операция).

Ассоциативный массив с точки зрения интерфейса удобно рассматривать как обычный массив, в котором в качестве индексов можно использовать не только целые числа, но и значения других типов — например, строки.

Поддержка ассоциативных массивов есть во многих интерпретируемых языках программирования высокого уровня, таких, как Perl, PHP, Python, Ruby, Tcl, JavaScript[1] и др. Для языков, которые не имеют встроенных средств работы с ассоциативными массивами, существует множество реализаций в виде библиотек.





Примеры

Примером ассоциативного массива является телефонный справочник. Значением в данном случае является совокупность «Ф. И. О. + адрес», а ключом — номер телефона. Один номер телефона имеет одного владельца, но один человек может иметь несколько номеров.

Расширения ассоциативного массива

Указанные три операции часто дополняются другими. Наиболее популярные расширения включают следующие операции:

  • CLEAR — удалить все записи
  • EACH — «пробежаться» по всем хранимым парам
  • MIN — найти пару с минимальным значением ключа
  • MAX — найти пару с максимальным значением ключа

В последних двух случаях необходимо, чтобы на ключах была определена операция сравнения.

Реализации ассоциативного массива

Существует множество различных реализаций ассоциативного массива.

Самая простая реализация может быть основана на обычном массиве, элементами которого являются пары (ключ, значение). Для ускорения операции поиска можно упорядочить элементы этого массива по ключу и осуществлять нахождение методом бинарного поиска. Но это увеличит время выполнения операции добавления новой пары, так как необходимо будет «раздвигать» элементы массива, чтобы в образовавшуюся пустую ячейку поместить новую запись.

Наиболее популярны реализации, основанные на различных деревьях поиска. Так, например, в стандартной библиотеке STL языка С++ контейнер map реализован на основе красно-чёрного дерева. В языках Ruby, Tcl, Python используется один из вариантов хэш-таблицы. Есть и другие реализации.

У каждой реализации есть свои достоинства и недостатки. Важно, чтобы все три операции выполнялись как в среднем, так и в худшем случае за время <math>O(\log n)</math>, где <math>n</math> — текущее количество хранимых пар. Для сбалансированных деревьев поиска (в том числе для красно-чёрных деревьев) это условие выполнено.

В реализациях, основанных на хэш-таблицах, среднее время оценивается как <math>O(1)</math>, что лучше, чем в реализациях, основанных на деревьях поиска. Но при этом не гарантируется высокая скорость выполнения отдельной операции: время операции INSERT в худшем случае оценивается как <math>O(n)</math>. Операция INSERT выполняется долго, когда коэффициент заполнения становится высоким и необходимо перестроить индекс хэш-таблицы.

Хэш-таблицы плохи также тем, что на их основе нельзя реализовать быстро работающие дополнительные операции MIN, MAX и алгоритм обхода всех хранимых пар в порядке возрастания или убывания ключей.

Поддержка ассоциативных массивов в языках программирования

Библиотека STL языка C++

Здесь приведено простейшее консольное приложение, предоставляющее интерфейс телефонной книжки. Оно реализовано на основе контейнера map.

#include <iostream>
#include <string>
#include <map>

using namespace std;

int main()
  {
    string cmd, name, phone;
    map< string, string > book;

    while( cin >> cmd )
      {
        if ( cmd == "add" )
          {
            cin >> name >> phone;
            book[ name ] = phone;
            cout << "Added" << endl;
          }
        else if ( cmd == "find" )
          {
            cin >> name;
            try {
              string v = book.at( name );
              cout << name << "'s phone is " << v << endl;
            }
            catch (const out_of_range& e) {
              cout << name << " not found" << endl;
            }
          }
        else if ( cmd == "del" )
          {
            cin >> name;
            book.erase( name );
            cout << "Deleted" << endl;
          }
        else if ( cmd == "view" )
          {
            for( auto& kv : book )
              cout << kv.first << "\t " << kv.second << endl;
          }
        else if ( cmd == "quit" )
          return 0;
        else
          cerr << "Bad command '" << cmd << "'" << endl;
    }

    return 0;
  }

C#

В C# для организации ассоциативного массива используется тип Dictionary:

Dictionary<string, string> dic = new Dictionary<string, string>();
dic.Add("Sally Smart", "555-9999");
dic.Add("John Doe", "555-1212");
dic.Add("J. Random Hacker", "553-1337");

// доступ к значению и показ сообщения
MessageBox.Show(dic["Sally Smart"]);

Для перебора элементов можно использовать цикл foreach. Порядок элементов не гарантируется. Если порядок важен, можно использовать SortedDictionary либо использовать метод-расширение Sort из LINQ.

// цикл по элементам с показом каждого элемента
foreach(KeyValuePair<string,string> kvp in dic)
{
    MessageBox.Show(String.Format("Phone number for {0} is {1}", kvp.Key, kvp.Value));
}

Java

В языке Java ассоциативный массив именуется отображением (map) и имеет соответствующий интерфейс в стандартном Java API: [docs.oracle.com/javase/8/docs/api/java/util/Map.html java.util.Map] Стандартный Java SDK включает в себя ряд реализаций этого интерфейса: HashMap, LinkedHashMap, ConcurrentHashMap, EnumMap, TreeMap и другие.

Map<String, String> map = new HashMap<String, String>();
map.put("a","apricot");
map.put("b","banana");
map.put("c","cherry");
String s = map.get("b");

Перебор элементов коллекции:

  for (Map.Entry<String,String> pair : map.entrySet()){
            System.out.printf("Ключ %s - Значение %s" , pair.getKey() ,pair.getValue());
        }

Ruby

Класс [programmingbulls.com/ruby-hash Hash] из стандартной библиотеки Ruby поддерживает операции [] (find), []= (insert), delete, each, keys, values, а также множество других.

Ниже приведён код с примерами выполнения отдельных операций.

# телефонная книга
phone_book = {'Ivan'=>'+74951234567', 'Anna'=>'+74951112233'}
phone_book['Ivan'] # равно '+74951234567'
phone_book['Peter'] = '+74952223344'  # добавили новую пару 
phone_book.delete('Anna') # удалили пару ('Anna', '+74951112233')

phone_book.each do |key, value| # выведем все записи
 puts "%20s %10s" % [key, value]
end

puts phone_book.values # вывести все номера телефонов

Ниже приведён код с реализацией консольного приложения «телефонная книжка».

require 'yaml'
book = {}
while line = STDIN.readline
  cmd, name, phone = line.split
  case cmd
  when 'insert'
    book[name] = phone
  when 'find'
    puts "#{name}'s phone is #{book[name]}"
  when 'del'
    book.delete(name)
  when 'view'
    book.each {|n,p| puts "#{n}\t #{p}" }
  when 'save'
    File.open(name,'w+'){|f| f.write(book.to_yaml)}
  when 'load'
    book = YAML.load_file(name)
  when 'quit'
    exit 0;
  else
    puts "Bad command '#{cmd}'";
  end
end

Python

Встроенный в Python тип ассоциативного массива называется словарём, элементами которого являются пары ключей и соответствующих им значений.

d1 = dict(a=10, b=20)
d2 = {'a': 10, 'b': 20}
d1[100] = 123
d2['c'] = 321
d1[100] = 1023

Здесь были показаны два способа написания литерала словаря и продемонстрировано, что ключом может быть объект любого неизменяемого (в нотации python) типа. Добавление нового объекта в словарь не требует предварительных проверок: если ранее ключу уже соответствовало некоторое значение, оно будет перезаписано (Подробнее см. [docs.python.org/tut/node7.html#SECTION007500000000000000000 Python Tutorial, Dictionaries] (англ.)). Другие операции со словарем:

if 'a' in d1:    # проверка наличия ключа
    del d1['a']        # удаление ключа (и значения)
val = d1.get('a', 'default value')   # получение значения по ключу или значения 
                                     # по умолчанию в случае отсутствия ключа
val = d1.setdefault('a', 'default value')   # получение значения по ключу или значения 
                       # по умолчанию в случае отсутствия ключа (при этом
                       # значение записывается в словарь)
d1.keys()              # список ключей
d1.values()            # список значений
d1.items()             # список пар ключ-значение

На Python весьма просто можно написать свой класс, который будет вести себя подобно словарю. Для этого необходимо лишь определить в своем классе соответствующие методы (см. [docs.python.org/ref/sequence-types.html Python Reference Manual, Emulating container types] (англ.)).

Расширить свойства встроенного типа словаря (dict) можно путём наследования класса, см. пример.

Perl

Ассоциативный массив (в Perl принято называть его хешем — англ. hash[2]) является встроенным типом данных. Хеш можно создавать поэлементно либо целиком, присвоив ему значения списка, в котором элементы записаны в виде пар «ключ — значение», внутри пары элементы могут разделяться как традиционным путём (например, запятой), так и при помощи оператора =>:

# Поэлементное присваивание
$hash{'horse'} = 'colt';
$hash{'sheep'} = 'lamb';

# Вывод количества ключей хеша. Напечатает 2
print scalar keys %hash;

# Присваивание списка
# Значения для ключей 'horse' и 'sheep' будут потеряны
%hash = (
    'cat' => 'kitten',
    'dog' => 'puppy',
    'cow' => 'calf',
);

print $hash{'cat'}; # Напечатает kitten
print keys %hash; # Вывод всех ключей. Напечатает catdogcow 
print values %hash; # Вывод всех значений. Напечатает kittenpuppycalf
print %hash; # Напечатает catkittencowcalfdogpuppy

Delphi

Delphi до 2007 версии не имело прямых средств работы с ассоциативными массивами. Однако вы можете имитировать ассоциативные массивы, используя различного рода списковые классы для этого: TBucketList, TObjectBucketList, THashedStringList, TStringList (как и все другие потомки TStrings, а также Memo, ListBox и др.). Например:

procedure TForm1.Button1Click(Sender: TObject);
var
  i : Integer;
  s : string;
begin
  with TStringList.Create do //создание анонимного списка (без объявления в var-секции)
    try
{1}   Values['Sally Smart'] := '555-9999'; // - добавление новой записи
{2}   Values['John Doe'   ] := '555-1212'; // - добавление ещё одной записи
{3}   Values['Sally Smart'] := '111-9999'; // - замена значения у существующей записи
{4}   Values['John Doe'   ] := '';         // - удаление записи со сдвигом списка

      SaveToFile(  'restore.txt'); // - сохранения списка во внешний файл
      LoadFromFile('restore.txt'); // - восстановление списка из файла

      s := Text;  // - сохранения списка в строке (единым текстом c CR/LF-ами)
      Text := s;  // - восстановление списка из строки (единым текстом c CR/LF-ами)

   // очистка и наполнение списка из специальной строки с настраиваемыми разделителями
   // Delimiter, QuoteChar - тремя записями пар [строковый ключ=значение ключа]
      DelimitedText :=
      '"Sally Smart=555-9999" "John Doe=555-1212" "J. Random Hacker=553-1337"';

   // TStringList, как и все потомки TStrings, наделены этими 4-мя свойствами (см. выше),
   // поэтому возможно их взаимодействие, в том числе с врапперами над Ассоциативными
   // массивами, хранящимися в системных списках: Memo-полях, ListBox'ах и т.д.:

      Assign(ListBox1.Items);  // - очистка и восстановление списка из ListBox1
      Memo1.Lines.Values['J. Random Hacker'] := '553-1337'; // - в Memo-поле
      AddStrings(Memo1.Lines); // - добавление строчек из списка Memo-поля

      Clear;                   // - просто очистка списка

   // доступ к значению и вывод его в message box
      ShowMessage(Values['Sally Smart']);

   // проход по ассоциативному массиву и доступ к ключам и значениям по индексу
      for i := 0 to Count - 1 do
        ShowMessage(Format('Number for %s: %s',[Names[i],ValueFromIndex[i]]));
    finally
      Free // автоуничтожение списка - Ассоциативного массива
    end;
end;

PL/SQL

СУБД Oracle начиная с версии 9.2.0 позволяет использовать в качестве ключей, помимо binary_integer и pls_integer, также и строки varchar2 с длиной до 32767:

declare
      type year_type is table of number index by varchar2(4000);
      year_sales year_type;
      tot_sales   number;
begin
      year_sales('1990') := 34000;
      year_sales('1991') := 45000;
      year_sales('1992') := 43000;

      tot_sales := year_sales('1990') + year_sales('1991') +
year_sales('1992');
      dbms_output.put_line('Total sales: ' || tot_sales);
end;

PHP

$hash = array(
    'cat' => 'kitten',
    'dog' => 'puppy',
    'cow' => 'calf'
);
print $hash['cat']; # Напечатает kitten
print_r( array_keys($hash) ); # Вывод всех ключей. 
print_r( array_values($hash) ); # Вывод всех значений.
print_r($hash); # Напечатает Array(cat=>'kitten', dog=>'puppy', cow=>'calf');

PureBasic

В PureBasic, начиная с версии 4.40, появилась встроенная поддержка ассоциативных массивов. Его называют картой (map). Пример обычного ассоциативного массива:

; Создали ассоциативный массив.
NewMap Country.s()

; Заполнение массива данными.
Country("GE") = "Germany"
Country("FR") = "France"
Country("UK") = "United Kingdom"

Debug Country("FR") ; Вывод результата "FR" в отладочное окно.

; Перебор всех элементов с отображением их значений в отладочном окне.
ForEach Country()
  Debug Country()
Next

Пример структурированного (каждым элементом является структура данных) ассоциативного массива.

  Structure Car ; Описание структуры.
    Weight.l
    Speed.l
    Price.l
  EndStructure

  NewMap Cars.Car() ; Создание структурированного ассоциативного массива.
  
  ; Заполнение массива данными.
  Cars("Ferrari F40")\Weight = 1000
  Cars()\Speed = 320
  Cars()\Price = 500000
  
  Cars("Lamborghini Gallardo")\Weight = 1200
  Cars()\Speed = 340
  Cars()\Price = 700000
  
  ; Перебор всех элементов с отображением их значений в отладочном окне.
  ForEach Cars()
    Debug "Car name: "+MapKey(Cars()) ; Имя ключа текущего элемента массива.
    Debug "Weight: "+Str(Cars()\Weight)
  Next

JavaScript

В ECMAScript 6 есть специальный объект Map, но он не везде поддерживается. Обычные массивы могут иметь только числовые индексы, потому для эмуляции ассоциативных массивов, ключами которых могут быть в том числе и строковые значения, можно использовать объекты.

Конструкция вида myVar = { key1: value1, key2: value2, … } создает объект myVar с набором полей, каждое из которых имеет свой ключ и значение. В дальнейшем доступ к элементам этого объекта может выполняться как с использованием нотации объектов и полей (myVar.key1), так и в нотации массивов и ключей (myvar['key1']).

var hash = {
   cat : 'kitten',
   'my-dog' : 'puppy', // если ключ содержит символы, отличные от алфавитно-цифровых, он заключается в кавычки
   cow : 'calf'
};

document.write(hash.cat);
document.write(hash['my-dog']);

hash.parrot = 'Kesha'; // добавление элемента в хэш выполняется присваиванием нужного значения по (пока еще) не существующему ключу
document.write(hash.parrot);

delete hash.parrot;  // для удаления элемента используется оператор delete
delete hash['my-dog'];
hash['my-parrot'] = 'Kesha';

document.write(hash['my-parrot']);

for (var p in hash) document.write(p + ' name is ' + hash[p]); // для обхода элементов хэша в JavaScript есть специальный вид цикла for .. in

См. также

Напишите отзыв о статье "Ассоциативный массив"

Ссылки

Классы или модули, реализующие ассоциативный массив или его расширение в различных языках программирования:

  • Контейнер map в STL
  • [msdn.microsoft.com/en-us/library/kf18ek11(VS.71).aspx страница помощи std::map на MSDN]
  • [www.sgi.com/tech/stl/Map.html страница помощи std::map на SGI STL]
  • [www.sgi.com/tech/stl/hash_map.html страница помощи std::hashmap SGI STL]
  • Класс [www.ruby-doc.org/core/classes/Hash.html Hash] в Ruby
  • Модуль [tcl.activestate.com/man/tcl8.0/TclCmd/array.htm Array] в Tcl
  • Класс [docs.python.org/lib/typesmapping.html Dict] в Python
  • Класс [goletas.com/solutions/collections/ TreeDictionary] в C#
  • Интерфейс [download.oracle.com/javase/6/docs/api/java/util/Map.html Map] в Java
  • [www.nist.gov/dads/HTML/assocarray.html NIST’s Dictionary of Algorithms and Data Structures: Associative Array]
  • [www.nist.gov/dads/HTML/dictionary.html NIST’s Dictionary of Algorithms and Data Structures: Association List]
  • [dmitriydenisov.com/php-mysql/massivy-php.html Массивы в PHP — Индексные, ассоциативные и многомерные массивы]

Примечания

  1. В JavaScript объекты поддерживают создание свойств с произвольным (строковым) ключом, таким образом, они реализуют также базовые свойства ассоциативного массива. См.: [learn.javascript.ru/object Объекты как ассоциативные массивы]. Учебник JavaScript. Проверено 20 декабря 2012. [www.webcitation.org/6D72tLIa1 Архивировано из первоисточника 23 декабря 2012].
  2. [perldoc.perl.org/perldata.html perldata - Perl data types] (англ.). Документация по языку Perl. Проверено 6 марта 2010.


К:Википедия:Статьи без источников (тип: не указан)

Отрывок, характеризующий Ассоциативный массив

– Pour en revenir a vos dames, on les dit bien belles. Quelle fichue idee d'aller s'enterrer dans les steppes, quand l'armee francaise est a Moscou. Quelle chance elles ont manque celles la. Vos moujiks c'est autre chose, mais voua autres gens civilises vous devriez nous connaitre mieux que ca. Nous avons pris Vienne, Berlin, Madrid, Naples, Rome, Varsovie, toutes les capitales du monde… On nous craint, mais on nous aime. Nous sommes bons a connaitre. Et puis l'Empereur! [Но воротимся к вашим дамам: говорят, что они очень красивы. Что за дурацкая мысль поехать зарыться в степи, когда французская армия в Москве! Они пропустили чудесный случай. Ваши мужики, я понимаю, но вы – люди образованные – должны бы были знать нас лучше этого. Мы брали Вену, Берлин, Мадрид, Неаполь, Рим, Варшаву, все столицы мира. Нас боятся, но нас любят. Не вредно знать нас поближе. И потом император…] – начал он, но Пьер перебил его.
– L'Empereur, – повторил Пьер, и лицо его вдруг привяло грустное и сконфуженное выражение. – Est ce que l'Empereur?.. [Император… Что император?..]
– L'Empereur? C'est la generosite, la clemence, la justice, l'ordre, le genie, voila l'Empereur! C'est moi, Ram ball, qui vous le dit. Tel que vous me voyez, j'etais son ennemi il y a encore huit ans. Mon pere a ete comte emigre… Mais il m'a vaincu, cet homme. Il m'a empoigne. Je n'ai pas pu resister au spectacle de grandeur et de gloire dont il couvrait la France. Quand j'ai compris ce qu'il voulait, quand j'ai vu qu'il nous faisait une litiere de lauriers, voyez vous, je me suis dit: voila un souverain, et je me suis donne a lui. Eh voila! Oh, oui, mon cher, c'est le plus grand homme des siecles passes et a venir. [Император? Это великодушие, милосердие, справедливость, порядок, гений – вот что такое император! Это я, Рамбаль, говорю вам. Таким, каким вы меня видите, я был его врагом тому назад восемь лет. Мой отец был граф и эмигрант. Но он победил меня, этот человек. Он завладел мною. Я не мог устоять перед зрелищем величия и славы, которым он покрывал Францию. Когда я понял, чего он хотел, когда я увидал, что он готовит для нас ложе лавров, я сказал себе: вот государь, и я отдался ему. И вот! О да, мой милый, это самый великий человек прошедших и будущих веков.]
– Est il a Moscou? [Что, он в Москве?] – замявшись и с преступным лицом сказал Пьер.
Француз посмотрел на преступное лицо Пьера и усмехнулся.
– Non, il fera son entree demain, [Нет, он сделает свой въезд завтра,] – сказал он и продолжал свои рассказы.
Разговор их был прерван криком нескольких голосов у ворот и приходом Мореля, который пришел объявить капитану, что приехали виртембергские гусары и хотят ставить лошадей на тот же двор, на котором стояли лошади капитана. Затруднение происходило преимущественно оттого, что гусары не понимали того, что им говорили.
Капитан велел позвать к себе старшего унтер офицера в строгим голосом спросил у него, к какому полку он принадлежит, кто их начальник и на каком основании он позволяет себе занимать квартиру, которая уже занята. На первые два вопроса немец, плохо понимавший по французски, назвал свой полк и своего начальника; но на последний вопрос он, не поняв его, вставляя ломаные французские слова в немецкую речь, отвечал, что он квартиргер полка и что ему ведено от начальника занимать все дома подряд, Пьер, знавший по немецки, перевел капитану то, что говорил немец, и ответ капитана передал по немецки виртембергскому гусару. Поняв то, что ему говорили, немец сдался и увел своих людей. Капитан вышел на крыльцо, громким голосом отдавая какие то приказания.
Когда он вернулся назад в комнату, Пьер сидел на том же месте, где он сидел прежде, опустив руки на голову. Лицо его выражало страдание. Он действительно страдал в эту минуту. Когда капитан вышел и Пьер остался один, он вдруг опомнился и сознал то положение, в котором находился. Не то, что Москва была взята, и не то, что эти счастливые победители хозяйничали в ней и покровительствовали ему, – как ни тяжело чувствовал это Пьер, не это мучило его в настоящую минуту. Его мучило сознание своей слабости. Несколько стаканов выпитого вина, разговор с этим добродушным человеком уничтожили сосредоточенно мрачное расположение духа, в котором жил Пьер эти последние дни и которое было необходимо для исполнения его намерения. Пистолет, и кинжал, и армяк были готовы, Наполеон въезжал завтра. Пьер точно так же считал полезным и достойным убить злодея; но он чувствовал, что теперь он не сделает этого. Почему? – он не знал, но предчувствовал как будто, что он не исполнит своего намерения. Он боролся против сознания своей слабости, но смутно чувствовал, что ему не одолеть ее, что прежний мрачный строй мыслей о мщенье, убийстве и самопожертвовании разлетелся, как прах, при прикосновении первого человека.
Капитан, слегка прихрамывая и насвистывая что то, вошел в комнату.
Забавлявшая прежде Пьера болтовня француза теперь показалась ему противна. И насвистываемая песенка, и походка, и жест покручиванья усов – все казалось теперь оскорбительным Пьеру.
«Я сейчас уйду, я ни слова больше не скажу с ним», – думал Пьер. Он думал это, а между тем сидел все на том же месте. Какое то странное чувство слабости приковало его к своему месту: он хотел и не мог встать и уйти.
Капитан, напротив, казался очень весел. Он прошелся два раза по комнате. Глаза его блестели, и усы слегка подергивались, как будто он улыбался сам с собой какой то забавной выдумке.
– Charmant, – сказал он вдруг, – le colonel de ces Wurtembourgeois! C'est un Allemand; mais brave garcon, s'il en fut. Mais Allemand. [Прелестно, полковник этих вюртембергцев! Он немец; но славный малый, несмотря на это. Но немец.]
Он сел против Пьера.
– A propos, vous savez donc l'allemand, vous? [Кстати, вы, стало быть, знаете по немецки?]
Пьер смотрел на него молча.
– Comment dites vous asile en allemand? [Как по немецки убежище?]
– Asile? – повторил Пьер. – Asile en allemand – Unterkunft. [Убежище? Убежище – по немецки – Unterkunft.]
– Comment dites vous? [Как вы говорите?] – недоверчиво и быстро переспросил капитан.
– Unterkunft, – повторил Пьер.
– Onterkoff, – сказал капитан и несколько секунд смеющимися глазами смотрел на Пьера. – Les Allemands sont de fieres betes. N'est ce pas, monsieur Pierre? [Экие дурни эти немцы. Не правда ли, мосье Пьер?] – заключил он.
– Eh bien, encore une bouteille de ce Bordeau Moscovite, n'est ce pas? Morel, va nous chauffer encore une pelilo bouteille. Morel! [Ну, еще бутылочку этого московского Бордо, не правда ли? Морель согреет нам еще бутылочку. Морель!] – весело крикнул капитан.
Морель подал свечи и бутылку вина. Капитан посмотрел на Пьера при освещении, и его, видимо, поразило расстроенное лицо его собеседника. Рамбаль с искренним огорчением и участием в лице подошел к Пьеру и нагнулся над ним.
– Eh bien, nous sommes tristes, [Что же это, мы грустны?] – сказал он, трогая Пьера за руку. – Vous aurai je fait de la peine? Non, vrai, avez vous quelque chose contre moi, – переспрашивал он. – Peut etre rapport a la situation? [Может, я огорчил вас? Нет, в самом деле, не имеете ли вы что нибудь против меня? Может быть, касательно положения?]
Пьер ничего не отвечал, но ласково смотрел в глаза французу. Это выражение участия было приятно ему.
– Parole d'honneur, sans parler de ce que je vous dois, j'ai de l'amitie pour vous. Puis je faire quelque chose pour vous? Disposez de moi. C'est a la vie et a la mort. C'est la main sur le c?ur que je vous le dis, [Честное слово, не говоря уже про то, чем я вам обязан, я чувствую к вам дружбу. Не могу ли я сделать для вас что нибудь? Располагайте мною. Это на жизнь и на смерть. Я говорю вам это, кладя руку на сердце,] – сказал он, ударяя себя в грудь.
– Merci, – сказал Пьер. Капитан посмотрел пристально на Пьера так же, как он смотрел, когда узнал, как убежище называлось по немецки, и лицо его вдруг просияло.
– Ah! dans ce cas je bois a notre amitie! [А, в таком случае пью за вашу дружбу!] – весело крикнул он, наливая два стакана вина. Пьер взял налитой стакан и выпил его. Рамбаль выпил свой, пожал еще раз руку Пьера и в задумчиво меланхолической позе облокотился на стол.
– Oui, mon cher ami, voila les caprices de la fortune, – начал он. – Qui m'aurait dit que je serai soldat et capitaine de dragons au service de Bonaparte, comme nous l'appellions jadis. Et cependant me voila a Moscou avec lui. Il faut vous dire, mon cher, – продолжал он грустным я мерным голосом человека, который сбирается рассказывать длинную историю, – que notre nom est l'un des plus anciens de la France. [Да, мой друг, вот колесо фортуны. Кто сказал бы мне, что я буду солдатом и капитаном драгунов на службе у Бонапарта, как мы его, бывало, называли. Однако же вот я в Москве с ним. Надо вам сказать, мой милый… что имя наше одно из самых древних во Франции.]
И с легкой и наивной откровенностью француза капитан рассказал Пьеру историю своих предков, свое детство, отрочество и возмужалость, все свои родственныеимущественные, семейные отношения. «Ma pauvre mere [„Моя бедная мать“.] играла, разумеется, важную роль в этом рассказе.
– Mais tout ca ce n'est que la mise en scene de la vie, le fond c'est l'amour? L'amour! N'est ce pas, monsieur; Pierre? – сказал он, оживляясь. – Encore un verre. [Но все это есть только вступление в жизнь, сущность же ее – это любовь. Любовь! Не правда ли, мосье Пьер? Еще стаканчик.]
Пьер опять выпил и налил себе третий.
– Oh! les femmes, les femmes! [О! женщины, женщины!] – и капитан, замаслившимися глазами глядя на Пьера, начал говорить о любви и о своих любовных похождениях. Их было очень много, чему легко было поверить, глядя на самодовольное, красивое лицо офицера и на восторженное оживление, с которым он говорил о женщинах. Несмотря на то, что все любовные истории Рамбаля имели тот характер пакостности, в котором французы видят исключительную прелесть и поэзию любви, капитан рассказывал свои истории с таким искренним убеждением, что он один испытал и познал все прелести любви, и так заманчиво описывал женщин, что Пьер с любопытством слушал его.
Очевидно было, что l'amour, которую так любил француз, была ни та низшего и простого рода любовь, которую Пьер испытывал когда то к своей жене, ни та раздуваемая им самим романтическая любовь, которую он испытывал к Наташе (оба рода этой любви Рамбаль одинаково презирал – одна была l'amour des charretiers, другая l'amour des nigauds) [любовь извозчиков, другая – любовь дурней.]; l'amour, которой поклонялся француз, заключалась преимущественно в неестественности отношений к женщине и в комбинация уродливостей, которые придавали главную прелесть чувству.
Так капитан рассказал трогательную историю своей любви к одной обворожительной тридцатипятилетней маркизе и в одно и то же время к прелестному невинному, семнадцатилетнему ребенку, дочери обворожительной маркизы. Борьба великодушия между матерью и дочерью, окончившаяся тем, что мать, жертвуя собой, предложила свою дочь в жены своему любовнику, еще и теперь, хотя уж давно прошедшее воспоминание, волновала капитана. Потом он рассказал один эпизод, в котором муж играл роль любовника, а он (любовник) роль мужа, и несколько комических эпизодов из souvenirs d'Allemagne, где asile значит Unterkunft, где les maris mangent de la choux croute и где les jeunes filles sont trop blondes. [воспоминаний о Германии, где мужья едят капустный суп и где молодые девушки слишком белокуры.]
Наконец последний эпизод в Польше, еще свежий в памяти капитана, который он рассказывал с быстрыми жестами и разгоревшимся лицом, состоял в том, что он спас жизнь одному поляку (вообще в рассказах капитана эпизод спасения жизни встречался беспрестанно) и поляк этот вверил ему свою обворожительную жену (Parisienne de c?ur [парижанку сердцем]), в то время как сам поступил во французскую службу. Капитан был счастлив, обворожительная полька хотела бежать с ним; но, движимый великодушием, капитан возвратил мужу жену, при этом сказав ему: «Je vous ai sauve la vie et je sauve votre honneur!» [Я спас вашу жизнь и спасаю вашу честь!] Повторив эти слова, капитан протер глаза и встряхнулся, как бы отгоняя от себя охватившую его слабость при этом трогательном воспоминании.
Слушая рассказы капитана, как это часто бывает в позднюю вечернюю пору и под влиянием вина, Пьер следил за всем тем, что говорил капитан, понимал все и вместе с тем следил за рядом личных воспоминаний, вдруг почему то представших его воображению. Когда он слушал эти рассказы любви, его собственная любовь к Наташе неожиданно вдруг вспомнилась ему, и, перебирая в своем воображении картины этой любви, он мысленно сравнивал их с рассказами Рамбаля. Следя за рассказом о борьбе долга с любовью, Пьер видел пред собою все малейшие подробности своей последней встречи с предметом своей любви у Сухаревой башни. Тогда эта встреча не произвела на него влияния; он даже ни разу не вспомнил о ней. Но теперь ему казалось, что встреча эта имела что то очень значительное и поэтическое.
«Петр Кирилыч, идите сюда, я узнала», – слышал он теперь сказанные сю слова, видел пред собой ее глаза, улыбку, дорожный чепчик, выбившуюся прядь волос… и что то трогательное, умиляющее представлялось ему во всем этом.
Окончив свой рассказ об обворожительной польке, капитан обратился к Пьеру с вопросом, испытывал ли он подобное чувство самопожертвования для любви и зависти к законному мужу.
Вызванный этим вопросом, Пьер поднял голову и почувствовал необходимость высказать занимавшие его мысли; он стал объяснять, как он несколько иначе понимает любовь к женщине. Он сказал, что он во всю свою жизнь любил и любит только одну женщину и что эта женщина никогда не может принадлежать ему.
– Tiens! [Вишь ты!] – сказал капитан.
Потом Пьер объяснил, что он любил эту женщину с самых юных лет; но не смел думать о ней, потому что она была слишком молода, а он был незаконный сын без имени. Потом же, когда он получил имя и богатство, он не смел думать о ней, потому что слишком любил ее, слишком высоко ставил ее над всем миром и потому, тем более, над самим собою. Дойдя до этого места своего рассказа, Пьер обратился к капитану с вопросом: понимает ли он это?