Jaki jest najlepszy sposób na iterację słownika?

Widziałem kilka różnych sposobów na iterację słownika w C#. Jest jakiś standardowy sposób?

Author: Uwe Keim, 2008-09-26

25 answers

foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}
 2993
Author: Pablo Fernandez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-20 23:14:01

Jeśli próbujesz użyć słownika generycznego w C#, tak jak używasz tablicy asocjacyjnej w innym języku:

foreach(var item in myDictionary)
{
  foo(item.Key);
  bar(item.Value);
}

Lub, jeśli potrzebujesz tylko iteracji nad kolekcją kluczy, użyj

foreach(var item in myDictionary.Keys)
{
  foo(item);
}

I na koniec, jeśli interesują Cię tylko wartości:

foreach(var item in myDictionary.Values)
{
  foo(item);
}

(zwróć uwagę, że słowo kluczowe var jest opcjonalną funkcją C# 3.0 i nowszych, możesz również użyć dokładnego typu kluczy / wartości tutaj)

 674
Author: Jacob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-02 19:19:26

W niektórych przypadkach może być potrzebny licznik, który może być dostarczony przez implementację for-loop. W tym celu LINQ zapewnia ElementAt co umożliwia:

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}
 112
Author: Maurício Fedatto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-04 12:25:28

Zależy od tego, czy szukasz kluczy, czy wartości...

Z MSDN Dictionary(TKey, TValue) Opis klasy:

// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
    Console.WriteLine("Key = {0}, Value = {1}", 
        kvp.Key, kvp.Value);
}

// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
    openWith.Values;

// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
    Console.WriteLine("Value = {0}", s);
}

// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
    openWith.Keys;

// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
    Console.WriteLine("Key = {0}", s);
}
 75
Author: J Healy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-09 10:16:06

Ogólnie rzecz biorąc, pytanie o "najlepszy sposób" bez konkretnego kontekstu jest jak pytanie, jaki jest najlepszy kolor.

Jedna ręka, jest wiele kolorów i nie ma najlepszego koloru. To zależy od potrzeby, a często również od smaku.

Z drugiej strony, Istnieje wiele sposobów na iterację słownika w C# i nie ma najlepszego sposobu. To zależy od potrzeby, a często również od smaku.

Najprostszy sposób

foreach (var kvp in items)
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Jeśli potrzebujesz tylko wartości (pozwala na wywołanie item, bardziej czytelny niż kvp.Value).

foreach (var item in items.Values)
{
    doStuff(item)
}

Jeśli potrzebujesz konkretnego porządku sortowania

Generalnie początkujący są zaskoczeni kolejnością wyliczania słownika.

LINQ zapewnia zwięzłą składnię, która pozwala określić kolejność (i wiele innych rzeczy), np.:

foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Znowu możesz potrzebować tylko wartości. LINQ zapewnia również zwięzłe rozwiązanie do:

  • iteracja bezpośrednio na wartości (pozwala na wywołanie jej item, bardziej czytelna niż kvp.Value)
  • ale sortowanie według kluczy

Oto jest:

foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
    doStuff(item)
}

Istnieje wiele innych rzeczywistych przypadków użycia, które możesz zrobić na podstawie tych przykładów. Jeśli nie potrzebujesz konkretnego zamówienia, po prostu trzymaj się" najprostszego sposobu " (patrz wyżej)!

 56
Author: Stéphane Gourichon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-23 15:38:47

Powiedziałbym, że foreach jest standardowym sposobem, choć oczywiście zależy to od tego, czego szukasz

foreach(var kvp in my_dictionary) {
  ...
}
Tego szukasz?
 38
Author: George Mauer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-17 15:59:56

Możesz również wypróbować to w dużych słownikach do przetwarzania wielowątkowego.

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});
 29
Author: Onur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-11 14:50:43

Jest wiele opcji. Mój ulubiony to KeyValuePair

Dictionary<string, object> myDictionary = new Dictionary<string, object>();
// Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary)
{
     // Do some interesting things
}

Możesz również użyć kolekcji kluczy i wartości

 22
Author: theo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-12 10:17:29

Doceniam, że to pytanie miało już wiele odpowiedzi, ale chciałem dorzucić trochę badań.

Iteracja nad słownikiem może być dość powolna w porównaniu z iteracją nad czymś takim jak tablica. W moich testach iteracja nad tablicą trwała 0.015003 sekundy, podczas gdy iteracja nad słownikiem (z taką samą liczbą elementów) trwała 0.0365073 sekundy, czyli 2.4 razy dłużej! Chociaż widziałem znacznie większe różnice. Dla porównania lista była gdzieś w od 0.00215043 sekund.

To jest jak porównywanie jabłek i pomarańczy. Chodzi mi o to, że iteracja słowników jest powolna.

Słowniki są zoptymalizowane pod kątem wyszukiwania, więc mając to na uwadze, stworzyłem dwie metody. Jeden po prostu wykonuje foreach, drugi iteracje kluczy, a następnie patrzy w górę.

public static string Normal(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var kvp in dictionary)
    {
        value = kvp.Value;
        count++;
    }

    return "Normal";
}

Ten ładuje klucze i zamiast nich iteruje (próbowałem też wciągnąć Klucze do łańcucha [], ale różnica była znikoma.

public static string Keys(Dictionary<string, string> dictionary)
{
    string value;
    int count = 0;
    foreach (var key in dictionary.Keys)
    {
        value = dictionary[key];
        count++;
    }

    return "Keys";
}

Z w tym przykładzie normalny test foreach wyniósł 0.0310062, a wersja keys-0.2205441. Ładowanie wszystkich klawiszy i iteracja wszystkich wyszukiwań jest wyraźnie dużo wolniejsze!

Na ostatni test wykonałem swoją iterację dziesięć razy, aby sprawdzić, czy są jakieś korzyści z używania klawiszy tutaj (w tym momencie byłem po prostu ciekaw):

Oto najbrutalniejsza metoda, jeśli pomoże Ci to wyobrazić sobie, co się dzieje.

private static string RunTest<T>(T dictionary, Func<T, string> function)
{            
    DateTime start = DateTime.Now;
    string name = null;
    for (int i = 0; i < 10; i++)
    {
        name = function(dictionary);
    }
    DateTime end = DateTime.Now;
    var duration = end.Subtract(start);
    return string.Format("{0} took {1} seconds", name, duration.TotalSeconds);
}

Tutaj normalny bieg foreach trwał 0.2820564 sekund (około dziesięć razy dłużej niż trwała pojedyncza iteracja - jak można się było spodziewać). 2.2249449 sekund

Edited To Add: Po przeczytaniu kilku innych odpowiedzi zadałem sobie pytanie, co by się stało, gdybym użył słownika zamiast słownika. W tym przykładzie tablica zajęła 0.0120024 sekund, lista 0.0185037 sekund, a Słownik 0.0465093 sekund. Rozsądnie jest oczekiwać, że typ danych ma wpływ na to, o ile słownik jest wolniejszy.

Co? Czy moje wnioski ?

  • unikaj iteracji nad słownikiem, jeśli możesz, są one znacznie wolniejsze niż iteracja nad tablicą z tymi samymi danymi.
  • jeśli zdecydujesz się na iterację nad słownikiem, nie próbuj być zbyt sprytny, chociaż wolniej możesz zrobić o wiele gorzej niż używając standardowej metody foreach.
 22
Author: Liath,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-28 12:22:57

Zasugerowałeś poniżej iterację

Dictionary<string,object> myDictionary = new Dictionary<string,object>();
//Populate your dictionary here

foreach (KeyValuePair<string,object> kvp in myDictionary) {
    //Do some interesting things;
}

FYI, foreach nie działa, jeśli wartość jest typu object.

 9
Author: George Stocker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-12 16:01:15

Z .NET Framework 4.7 można użyć rozkładu

var fruits = new Dictionary<string, int>();
...
foreach (var (fruit, number) in fruits)
{
    Console.WriteLine(fruit + ": " + number);
}

Aby ten kod działał w niższych wersjach C#, dodaj System.ValueTuple NuGet package i napisz gdzieś

public static class MyExtensions
{
    public static void Deconstruct<T1, T2>(this KeyValuePair<T1, T2> tuple,
        out T1 key, out T2 value)
    {
        key = tuple.Key;
        value = tuple.Value;
    }
}
 9
Author: Pavel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-17 15:18:55

Najprostsza forma do iteracji słownika:

foreach(var item in myDictionary)
{ 
    Console.WriteLine(item.Key);
    Console.WriteLine(item.Value);
}
 7
Author: Ron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-13 15:35:17

Czasami, jeśli potrzebujesz tylko wartości do wyliczenia, użyj kolekcji wartości słownika:

foreach(var value in dictionary.Values)
{
    // do something with entry.Value only
}

Zgłoszone przez ten post, który stwierdza, że jest to najszybsza Metoda: http://alexpinsker.blogspot.hk/2010/02/c-fastest-way-to-iterate-over.html

 6
Author: ender,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-02 01:55:08

Znalazłem tę metodę w dokumentacji dla klasy DictionaryBase na MSDN:

foreach (DictionaryEntry de in myDictionary)
{
     //Do some stuff with de.Value or de.Key
}

To był jedyny, który udało mi się poprawnie funkcjonować w klasie, która odziedziczyła po bazie słownikowej.

 5
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-17 23:51:39

Używając C# 7 , dodaj tę metodę rozszerzenia do dowolnego projektu Twojego rozwiązania:

public static class IDictionaryExtensions
{
    public static IEnumerable<(TKey, TValue)> Tuples<TKey, TValue>(
        this IDictionary<TKey, TValue> dict)
    {
        foreach (KeyValuePair<TKey, TValue> kvp in dict)
            yield return (kvp.Key, kvp.Value);
    }
}


I użyj tej prostej składni

foreach (var(id, value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


Albo Ten, jeśli wolisz

foreach ((string id, object value) in dict.Tuples())
{
    // your code using 'id' and 'value'
}


W miejsce tradycyjnego

foreach (KeyValuePair<string, object> kvp in dict)
{
    string id = kvp.Key;
    object value = kvp.Value;

    // your code using 'id' and 'value'
}


Metoda rozszerzenia przekształca {[4] } twojego IDictionary<TKey, TValue> w silnie wpisaną tuple, co pozwala na użycie nowej wygodnej składni.

Konwertuje - tylko-wymagane wpisy słownikowe do tuples, więc nie konwertuje całego słownika na tuples, więc nie ma z tym żadnych problemów związanych z wydajnością.

Istnieje tylko niewielki koszt wywołania metody rozszerzenia do tworzenia tuple w porównaniu z bezpośrednim użyciem KeyValuePair, co nie powinno być problemem, jeśli przypisujesz właściwości KeyValuePair Key i Value do nowych zmiennych pętli.

W praktyce ta nowa składnia bardzo dobrze pasuje do większości przypadków, z wyjątkiem niskiej wydajności ultra-wysokiej scenariusze, w których nadal masz możliwość po prostu nie używać go w danym miejscu.

Zobacz to: blog MSDN-nowe funkcje w C# 7

 5
Author: sɐunıɔןɐqɐp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-01 20:38:35

Skorzystam z. NET 4.0+ i podam zaktualizowaną odpowiedź na pierwotnie zaakceptowaną:

foreach(var entry in MyDic)
{
    // do something with entry.Value or entry.Key
}
 3
Author: yazanpro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-01 23:17:52

Standardowy sposób iteracji nad słownikiem, zgodnie z oficjalną dokumentacją MSDN to:

foreach (DictionaryEntry entry in myDictionary)
{
     //Read entry.Key and entry.Value here
}
 3
Author: Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-28 10:58:55

Jeśli powiedzmy, chcesz iterować nad kolekcją wartości domyślnie, wierzę, że możesz zaimplementować IEnumerable, gdzie T jest typem obiektu values w słowniku, A "this" jest słownikiem.

public new IEnumerator<T> GetEnumerator()
{
   return this.Values.GetEnumerator();
}
 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-09 04:16:11

Od C # 7 można dekonstruować obiekty na zmienne. Uważam, że jest to najlepszy sposób na iterację słownika.

Przykład:

Utwórz metodę rozszerzenia na KeyValuePair<TKey, TVal>, która ją dekonstruuje:

public static void Deconstruct<TKey, TVal>(this KeyValuePair<TKey, TVal> pair, out TKey, out TVal val)
{
   key = pair.Key;
   val = pair.Value;
}

Iteruj nad dowolnym Dictionary<TKey, TVal> w następujący sposób

// Dictionary can be of any types, just using 'int' and 'string' as examples.
Dictionary<int, string> dict = new Dictionary<int, string>();

// Deconstructor gets called here.
foreach (var (key, value) in dict)
{
   Console.WriteLine($"{key} : {value}");
}
 2
Author: Domn Werner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-11 18:05:23
var dictionary = new Dictionary<string, int>
{
    { "Key", 12 }
};

var aggregateObjectCollection = dictionary.Select(
    entry => new AggregateObject(entry.Key, entry.Value));
 1
Author: Pixar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-28 15:00:10

Chciałem tylko dodać mój 2 cent, ponieważ większość odpowiedzi dotyczy foreach-loop. Proszę spojrzeć na następujący kod:

Dictionary<String, Double> myProductPrices = new Dictionary<String, Double>();

//Add some entries to the dictionary

myProductPrices.ToList().ForEach(kvP => 
{
    kvP.Value *= 1.15;
    Console.Writeline(String.Format("Product '{0}' has a new price: {1} $", kvp.Key, kvP.Value));
});

Altought this adds a additional call of '.ToList ()", może wystąpić niewielka poprawa wydajności (jak wskazano tutaj foreach vs someList.Foreach () {} ), szczególnie podczas pracy z dużymi słownikami i pracy równolegle nie ma opcji / nie będzie miał żadnego efektu.

Należy również pamiętać, że nie będzie można przypisać wartości do właściwość 'Value' wewnątrz pętli foreach. Z drugiej strony, będziesz w stanie manipulować "kluczem", jak również, prawdopodobnie wpakować cię w kłopoty w czasie wykonywania.

Kiedy chcesz po prostu "odczytać" klucze i wartości, możesz również użyć IEnumerable.Select ().

var newProductPrices = myProductPrices.Select(kvp => new { Name = kvp.Key, Price = kvp.Value * 1.15 } );
 1
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:47

Napisałem rozszerzenie do loop over a dictionary.

public static class DictionaryExtension
{
    public static void ForEach<T1, T2>(this Dictionary<T1, T2> dictionary, Action<T1, T2> action) {
        foreach(KeyValuePair<T1, T2> keyValue in dictionary) {
            action(keyValue.Key, keyValue.Value);
        }
    }
}

Wtedy możesz zadzwonić

myDictionary.ForEach((x,y) => Console.WriteLine(x + " - " + y));
 1
Author: Steven Delrue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-08 07:07:02

Dictionary jest to OGÓLNA Klasa kolekcji w c# i przechowuje dane w formacie wartości klucza.Klucz musi być unikalny i nie może być null natomiast wartość może być duplikowana i null.As każda pozycja w słowniku jest traktowana jako KeyValuePair struktura reprezentująca klucz i jego wartość. i dlatego powinniśmy przyjąć element typu KeyValuePair podczas iteracji elementu.Poniżej znajduje się przykład.

Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1,"One");
dict.Add(2,"Two");
dict.Add(3,"Three");

foreach (KeyValuePair<int, string> item in dict)
{
    Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
}
 0
Author: Sheo Dayal Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-16 11:25:37

Oprócz najwyższych pozycji w rankingu, gdzie istnieje dyskusja między użyciem

foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

Lub

foreach(var entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

Najbardziej kompletny jest następujący, ponieważ możesz zobaczyć Typ słownika z inicjalizacji, KVP jest KeyValuePair

var myDictionary = new Dictionary<string, string>(x);//fill dictionary with x

foreach(var kvp in myDictionary)//iterate over dictionary
{
    // do something with kvp.Value or kvp.Key
}
 0
Author: BigChief,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-19 20:50:39

Słowniki są listami specjalnymi, podczas gdy każda wartość na liście ma klucz który jest również zmienną. Dobrym przykładem słownika jest książka telefoniczna.

   Dictionary<string, long> phonebook = new Dictionary<string, long>();
    phonebook.Add("Alex", 4154346543);
    phonebook["Jessica"] = 4159484588;

Zauważ, że definiując słownik, musimy podać rodzajnik definicja z dwoma typami-typem klucza i typem wartości. W tym przypadku kluczem jest łańcuch znaków, podczas gdy wartością jest liczba całkowita.

Istnieją również dwa sposoby dodawania pojedynczej wartości do słownika, albo za pomocą nawiasów operatora lub przy użyciu metody Add.

Aby sprawdzić, czy Słownik zawiera określony klucz, możemy użyć metody ContainsKey:

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

if (phonebook.ContainsKey("Alex"))
{
    Console.WriteLine("Alex's number is " + phonebook["Alex"]);
}

Aby usunąć element ze słownika, możemy użyć metody Remove. Usuwanie elementu ze słownika za pomocą jego klucza jest szybkie i bardzo skuteczne. Podczas usuwania elementu z listy przy użyciu jego wartości, Proces jest powolny i nieefektywny, w przeciwieństwie do funkcji usuwania słownika.

Dictionary<string, long> phonebook = new Dictionary<string, long>();
phonebook.Add("Alex", 415434543);
phonebook["Jessica"] = 415984588;

phonebook.Remove("Jessica");
Console.WriteLine(phonebook.Count);
 -2
Author: Amit Kumar Verma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-15 14:19:14