Соответствует первой части строк filepath - PullRequest
1 голос
/ 04 мая 2011

У меня есть простой класс, подобный следующему:

class Record
{
    public Record(string fp1, string fp2, string fp3)
    {
        Filepath1 = fp1;
        Filepath2 = fp2;
        Filepath3 = fp3;
    }

    public string Filepath1 { get; private set; }
    public string Filepath2 { get; private set; }
    public string Filepath3 { get; private set; }
}

Каждый из этих путей к файлам будет очень похожим (и очень длинным) и будет отличаться только для последних нескольких символов пути к файлу.

Теперь я хочу, чтобы в памяти было несколько тысяч таких записей, и я хотел бы, чтобы эти записи занимали меньше оперативной памяти. Поэтому я пытаюсь придумать способы оптимизации использования памяти, и вот одно из решений, которое я нашел:

class Record
{
    private string _baseFilepath;
    private string _fp1;
    private string _fp2;
    private string _fp3;
    public Record(string fp1, string fp2, string fp3)
    {
        _baseFilepath = /*get common first part of filepaths*/;
        _fp1 = /*last part of fp1*/;
        _fp2 = /*last part of fp2*/;
        _fp3 = /*last part of fp3*/;
    }

    public string Filepath1
    {
        get { return _baseFilepath + _fp1; }
    }

    public string Filepath2
    {
        get { return _baseFilepath + _fp2; }
    }

    public string Filepath3
    {
        get { return _baseFilepath + _fp3; }
    }
}

Вы можете видеть, что я мог бы сэкономить много оперативной памяти, особенно с очень длинными путями к файлам, где отличаются только последние несколько символов. Вопрос в том, есть ли простой способ получить общую первую часть пути к файлу?

EDIT: В памяти может быть до 700 000 записей, а у реального производственного класса есть еще несколько путей к файлам. Я пытаюсь сделать приложение как можно более легким, и в то же время стараюсь сделать оптимизации максимально простыми для простоты.

Ответы [ 3 ]

4 голосов
/ 04 мая 2011

Это будет сделано:

public static string GetCommonStart(string fp1, string fp2, string fp3)
{
    int idx = 0;
    int minLength = Math.Min(Math.Min(fp1.Length, fp2.Length), fp3.Length);
    while (idx < minLength && fp1[idx] == fp2[idx] && fp2[idx] == fp3[idx])
       idx++;
    return fp1.Substring(0, idx);
}
1 голос
/ 04 мая 2011

Считайте, что это дополнительный ответ, дающий альтернативное предложение, а не прямой ответ на вашу проблему (которая уже была предоставлена).

Если возможно, я бы разбил эти пути к файлам на base и suffix при первой возможности, а затем прошел бы таким образом через всю вашу систему.

Это применимо, если

  • вы сами генерируете эти пути к файлам, где-то в вашей системе
  • вы читаете файлы из известного и конечного набора местоположений

Вы бы просто имели набор base путей к файлам, и каждый Filepath ссылается один раз на эти base значения, а также содержит свое собственное значение suffix.

В зависимости от количества base путей к файлам и от того, как они были определены, это будет значительно более эффективно использовать память. Ваше текущее решение дает в третьем случае лучшее использование памяти (каждые три пути к файлам лучше оптимизировать в один путь к файлу). Также имеет смысл хранить этот объект (filepath) согласованным образом во всем приложении.

1 голос
/ 04 мая 2011

Вы можете использовать что-то вроде этого, если это действие не критично для вас:

public static class StringExtensions
{
    public static string GetCommonPrefix(string a, string b)
    {
        int commonPrefixLength = 0;
        int minimumLength = Math.Min(a.Length, b.Length);

        for (int i = 0; i < minimumLength; i++)
        {
            if (a[i] == b[i])
            {
                commonPrefixLength++;
            }
        }

        return a.Substring(0, commonPrefixLength);
    }

    public static string GetCommonPrefix(params string[] strings)
    {
        return strings.Aggregate(GetCommonPrefix);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...