Создать вложенный список (массив) строк из списка строк - PullRequest
0 голосов
/ 13 февраля 2019

У меня есть список имен.Из них я хочу создать новый список списков (или зубчатый массив, если это работает лучше), где списки нижнего уровня содержат варианты имен.

Основная идея заключается в том, что вы берете имяи удаляйте одну букву за раз, чтобы создать список, содержащий все эти творения, а также оригинальное имя.Так, например, если ваши имена «bob» и «alice», я хочу вывести

[["bo", "bb","ob","bob"], ["alic", "alie", "alce", "aice", "lice", "alice"]].

Я могу легко сделать это только для одного имени, но я сталкиваюсь с проблемами, которые не могу решить, когдаЯ пытаюсь создать такой вложенный список (я относительно новичок в C #).Вот игрушечный пример того, что я пробовал:

List<string> names = new List<string>()
{
    "alice",
    "bob",
    "curt"
};

//initialize jagged array
string[][] modifiedNames = new string[names.Count][];

        //iterate over all names in "names" list
        foreach(string name in names)
        {
            int nameIndex = names.IndexOf(name);

            //initialize lower level of array
            modifiedNames[nameIndex] = new string[name.Length];

            //create variations of a given name
            for (int i = 0; i < name.Length; i++)
            {
                string newName = name.Substring(0, i) + name.Substring(i + 1);

                if (modNames[nameIndex].Contains(newName) == false)
                    modNames[nameIndex].Add(newName);
            }
            modName.Add(name);

        }

Я пробовал несколько его версий, как со списками, так и с массивами, но безрезультатно.В этом случае я получаю сообщение об ошибке:

'string []' не содержит определения для 'Add' и недоступного метода расширения 'Add', принимающего первый аргумент типа 'string []'может быть найдено (вам не хватает директивы using или ссылки на сборку?)

Большое спасибо за помощь!

Ответы [ 5 ]

0 голосов
/ 14 февраля 2019

Я думаю, что это довольно простой способ:

List<string> names = new List<string>()
{
    "alice",
    "bob",
    "curt"
};

string[][] modifiedNames =
    names
        .Select(name =>
            Enumerable
                .Range(0, name.Length)
                .Select(x => name.Substring(0, x) + name.Substring(x + 1))
                .Concat(new [] { name })
                .ToArray())
        .ToArray();

Это дает:

modifiedNames

0 голосов
/ 14 февраля 2019

Вы можете упростить свою логику, используя String.Remove(i, 1) для удаления по одному символу за раз, повторяя значения i для длины строки.Вы можете написать свой запрос в виде одной строки:

var result = names.Select(name => name.Select((_, i) => name.Remove(i, 1)).Reverse().Concat(new[] { name }).ToList()).ToList();

Переформатирован для удобства чтения:

var result = names
    .Select(name => 
        name.Select((_, i) => name.Remove(i, 1))
            .Reverse()
            .Concat(new[] { name })
            .ToList())
    .ToList();
0 голосов
/ 13 февраля 2019

Во-первых, эта ошибка говорит о том, что для массива нет функции Add().Как указывает ДжонБ, здесь, вероятно, лучше подойдет List.

Во-вторых, мне все равно не нравится string[][].Я бы использовал IDictionary<string, IList<string>>, сохраняя ваше исходное имя в качестве ключа, и измененные имена в качестве значения.Таким образом, исходная и измененная версии хранятся вместе, и вам не нужно сопоставлять names с modifiedNames (одна из которых является List, а другая (в настоящее время) массивом).

IDictionary<string, IList<string>> names = new Dictionary<string, IList<string>>();

names.Add("alice", new List<string>());
names.Add("bob", new List<string>());
names.Add("curt", new List<string>());

foreach (KeyValuePair<string, IList<string>> name in names)
{
    for (int i = 0; i < name.Key.Length; i++)
    {
        string newName = name.Key.Substring(0, i) + name.Key.Substring(i + 1);

        if (!name.Value.Contains(newName))
        {
            name.Value.Add(newName);
        }
    }
}

Надеюсь, это поможет.

0 голосов
/ 13 февраля 2019

Я бы сделал это в два этапа.Сначала напишите простой метод, который получит список вариантов имени для одного имени.Мы можем упростить код, используя некоторые System.Linq методы расширения, такие как Select() и ToList().Оператор Select ниже обрабатывает строку как массив символов, и для каждого символа t с индексом i он выбирает подстроку от name до этого символа и добавляет подстроку из name после этого символа, возвращая IEnumerable<string>, из которого мы создаем новый List<string>.Затем мы наконец добавляем исходный name в список и возвращаем его:

public static List<string> GetNameVariations(string name)
{
    var results = name.Select((t, i) =>
        name.Substring(0, i) + name.Substring(i + 1, name.Length - (i + 1)))
        .ToList();

    results.Add(name);

    return results;
}

И затем мы можем использовать этот метод для получения List<List<string>> имен из списка имен, используя другой метод.Здесь мы вызываем GetNameVariations для каждого имени в names (который возвращает новый List<string> для каждого имени) и возвращаем эти списки в новом List<List<string>>:

public static List<List<string>> GetNameVariations(List<string> names)
{
    return names.Select(GetNameVariations).ToList();
}

Используется,это может выглядеть (используя ваш пример):

private static void Main()
{
    var names = new List<string> {"bob", "alice", "curt"};

    foreach (var nameVariations in GetNameVariations(names))
    {
        Console.WriteLine(string.Join(", ", nameVariations));
    }

    GetKeyFromUser("\nDone! Press any key to exit...");
}

Вывод

![![enter image description here

0 голосов
/ 13 февраля 2019

Как насчет использования списка списков (строки), пока вы работаете в методе, и затем преобразования его в массив массива перед возвратом?Или даже просто вернуть список списка, если тип возвращаемого значения не указан в камне?

Вот предложение:

    var names = new List<string>()
    {
        "alice",
        "bob",
        "curt"
    };

    var nameVariations = new List<List<string>>();
    foreach (var name in names)
    {
        var variationsOfName = new List<string>();
        for (int i = 0; i < name.Length; i++)
        {
            var newName = name.Substring(0, i) + name.Substring(i + 1);

            if (!variationsOfName.Contains(newName))
            {
                variationsOfName.Add(newName);
            }
        }

        nameVariations.Add(variationsOfName);
    }

    return nameVariations.Select(variationsOfName => variationsOfName.ToArray()).ToArray();

Примечание: для компиляции вам понадобитсядобавить Linq (используя System.Linq;).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...