我有一个名字列表。通过这些,我想创建一个新的列表列表(或锯齿状数组,如果效果更好),其中较低级别的列表包含名称的变体。
基本思想是,您取一个名字并一次删除一个字母,以创建一个包含所有这些作品以及原始名称的列表。例如,如果您的名字是“ 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指令或程序集引用? ?)
非常感谢您的帮助!
答案 0 :(得分:0)
在使用方法时如何使用列表列表(字符串),然后在返回之前将其转换为数组数组呢?如果返回类型不是一成不变的,甚至可以返回列表列表?
这是一个建议:
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;)。
答案 1 :(得分:0)
首先,该错误告诉您数组没有Add()
函数。正如JohnB所指出的,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);
}
}
}
希望这会有所帮助。
答案 2 :(得分:0)
我将分两步执行此操作。首先,编写一个简单的方法,该方法将获取单个名称的名称变体列表。我们可以使用某些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...");
}
输出
答案 3 :(得分:0)
通过使用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();
答案 4 :(得分:0)