C# 函数式的实现方法

C# 函数式的实现方法,c#,linq,C#,Linq,我有以下方法: private List<string> CreateSegments(string virtualPath) { List<string> segments = new List<string>(); int i = virtualPath.IndexOf('/', 1); while (i >= 0 && i < virtualPath.Length) { var

我有以下方法:

private List<string> CreateSegments(string virtualPath)
{
    List<string> segments = new List<string>();
    int i = virtualPath.IndexOf('/', 1);
    while (i >= 0 && i < virtualPath.Length)
    {
        var segment = virtualPath.Substring(0, i);
        if (!string.IsNullOrWhiteSpace(segment))
        {
            segments.Add(segment);
            segments.Add(VirtualPathUtility.Combine(segment, "default"));
        }
        i = virtualPath.IndexOf('/', i + 1);
    }
    segments.Add(virtualPath);
    segments.Add(VirtualPathUtility.Combine(virtualPath, "default"));

    return segments;
}
其中
virtualPath
将包含值
“/path/to/file”

编辑:
string.Format(“{0}/{1}”,…)
更改为
virtualPath实用性。合并(…,…)


有什么想法吗?

一种方法是递增地选择路径段,然后用空字符串“连接”它,然后使用
“/default”
获得两种变体:

string path = @"/path/to/file";

string temp = "";

var query = path.Split('/')
                .Where(s => !string.IsNullOrEmpty(s))
                .Select((p) => {temp += ("/" + p); return temp;} )
                .SelectMany(s => new[]{"","/default"}.Select (d => s + d) );

如果您首先定义这样的扩展方法:

public static IEnumerable<int> SplitIndexes(this string subject, char search)
{
    for(var i = 1; i < subject.Length; i++)
    {
        if(subject[i] == search)
        {
            yield return i;
        }
    }

    yield return subject.Length;
}
var endings = new string[] { string.Empty, "default" }; // Note: no / before default
var results = 
    from i in virtualPath.SplitIndexes(Path.DirectorySeparatorChar)
    from e in endings
    select Path.Combine(virtualPath.Substring(0, i), e);
public static IEnumerable<string> EnumerateSegments( this IEnumerable<string> segments )
{
  StringBuilder sb = new StringBuilder() ;
  foreach ( string segment in segements )
  {
    sb.Append( Path.DirectorySeparatorChar ).Append( segment ) ;
    yield return sb.ToString() ;
    int n = sb.Length ;
    sb.Append( Path.DirectorySeparatorChar ).Append("default") ;
    yield return sb.ToString() ;
    sb.Length = n ;
  }
}
private List<string> CreateSegments(string virtualPath)
{
    return virtualPath.Split('/')
                      .Scan((s1, s2) => s1 + '/' + s2)
                      .Skip(1)
                      .SelectMany(p => new[] { p, p + "/default" })
                      .ToList();
}
或者,如果您更喜欢查询语法:

var endings = new string[] { string.Empty, "/default" };
var virtualPath = "/path/to/file";
var results = virtualPath.SplitIndexes('/')
                         .SelectMany(i => endings.Select(e => virtualPath.Substring(0, i) + e));
结果将是:

/path
/path/default
/path/to
/path/to/default
/path/to/file
/path/to/file/default
正如其他人所建议的,您可以通过使用
Path.combined
,以一种更独立于平台的方式实现这一点,如下所示:

public static IEnumerable<int> SplitIndexes(this string subject, char search)
{
    for(var i = 1; i < subject.Length; i++)
    {
        if(subject[i] == search)
        {
            yield return i;
        }
    }

    yield return subject.Length;
}
var endings = new string[] { string.Empty, "default" }; // Note: no / before default
var results = 
    from i in virtualPath.SplitIndexes(Path.DirectorySeparatorChar)
    from e in endings
    select Path.Combine(virtualPath.Substring(0, i), e);
public static IEnumerable<string> EnumerateSegments( this IEnumerable<string> segments )
{
  StringBuilder sb = new StringBuilder() ;
  foreach ( string segment in segements )
  {
    sb.Append( Path.DirectorySeparatorChar ).Append( segment ) ;
    yield return sb.ToString() ;
    int n = sb.Length ;
    sb.Append( Path.DirectorySeparatorChar ).Append("default") ;
    yield return sb.ToString() ;
    sb.Length = n ;
  }
}
private List<string> CreateSegments(string virtualPath)
{
    return virtualPath.Split('/')
                      .Scan((s1, s2) => s1 + '/' + s2)
                      .Skip(1)
                      .SelectMany(p => new[] { p, p + "/default" })
                      .ToList();
}

到目前为止,提供的答案更为简洁,但这是我得出的结论:

public static IEnumerable<string> PossiblePaths(string basePath)
{
    return PossiblePaths(basePath.Split(new[] { "/" }, 
                         StringSplitOptions.RemoveEmptyEntries));
}

private static IEnumerable<string> PossiblePaths(IEnumerable<string> segments, 
                                                 string current = "/")
{
    if (segments.Count() == 0)
    {
        return new string[0];
    }
    else
    {
        string next = current + segments.First();
        return new[] { next, next + "/default" }
                         .Concat(PossiblePaths(segments.Skip(1), next + "/"));
    }
}
公共静态IEnumerable可能路径(字符串基路径)
{
返回可能路径(basePath.Split(new[]{”/“},
StringSplitOptions.RemoveEmptyEntries);
}
私有静态IEnumerable可能路径(IEnumerable段,
字符串current=“/”)
{
if(segments.Count()==0)
{
返回新字符串[0];
}
其他的
{
字符串next=当前+段。First();
返回新[]{next,next+“/default”}
.Concat(可能的路径(段.跳过(1),下一个+“/”);
}
}
类似这样的内容:

public static IEnumerable<int> SplitIndexes(this string subject, char search)
{
    for(var i = 1; i < subject.Length; i++)
    {
        if(subject[i] == search)
        {
            yield return i;
        }
    }

    yield return subject.Length;
}
var endings = new string[] { string.Empty, "default" }; // Note: no / before default
var results = 
    from i in virtualPath.SplitIndexes(Path.DirectorySeparatorChar)
    from e in endings
    select Path.Combine(virtualPath.Substring(0, i), e);
public static IEnumerable<string> EnumerateSegments( this IEnumerable<string> segments )
{
  StringBuilder sb = new StringBuilder() ;
  foreach ( string segment in segements )
  {
    sb.Append( Path.DirectorySeparatorChar ).Append( segment ) ;
    yield return sb.ToString() ;
    int n = sb.Length ;
    sb.Append( Path.DirectorySeparatorChar ).Append("default") ;
    yield return sb.ToString() ;
    sb.Length = n ;
  }
}
private List<string> CreateSegments(string virtualPath)
{
    return virtualPath.Split('/')
                      .Scan((s1, s2) => s1 + '/' + s2)
                      .Skip(1)
                      .SelectMany(p => new[] { p, p + "/default" })
                      .ToList();
}
公共静态IEnumerable枚举段(此IEnumerable段)
{
StringBuilder sb=新的StringBuilder();
foreach(分段中的字符串段)
{
sb.Append(Path.directoryseportorchar).Append(segment);
让某人返回字符串();
int n=sb.长度;
sb.Append(Path.directoryseportorchar.Append(“默认”);
让某人返回字符串();
sb.长度=n;
}
}

应该这样做。

调用您要查找的高阶函数。在普通LINQ中没有这样的函数,但您可以在中找到它。使用该选项,您的代码可以如下所示:

public static IEnumerable<int> SplitIndexes(this string subject, char search)
{
    for(var i = 1; i < subject.Length; i++)
    {
        if(subject[i] == search)
        {
            yield return i;
        }
    }

    yield return subject.Length;
}
var endings = new string[] { string.Empty, "default" }; // Note: no / before default
var results = 
    from i in virtualPath.SplitIndexes(Path.DirectorySeparatorChar)
    from e in endings
    select Path.Combine(virtualPath.Substring(0, i), e);
public static IEnumerable<string> EnumerateSegments( this IEnumerable<string> segments )
{
  StringBuilder sb = new StringBuilder() ;
  foreach ( string segment in segements )
  {
    sb.Append( Path.DirectorySeparatorChar ).Append( segment ) ;
    yield return sb.ToString() ;
    int n = sb.Length ;
    sb.Append( Path.DirectorySeparatorChar ).Append("default") ;
    yield return sb.ToString() ;
    sb.Length = n ;
  }
}
private List<string> CreateSegments(string virtualPath)
{
    return virtualPath.Split('/')
                      .Scan((s1, s2) => s1 + '/' + s2)
                      .Skip(1)
                      .SelectMany(p => new[] { p, p + "/default" })
                      .ToList();
}
private List CreateSegments(字符串virtualPath)
{
返回virtualPath.Split(“/”)
.Scan((s1,s2)=>s1+'/'+s2)
.Skip(1)
.SelectMany(p=>new[]{p,p+“/default”})
.ToList();
}
这假设您的路径始终是以
/
开头的绝对路径。对于相对路径,您需要删除
.Skip(1)
部分


如果您不想只为这一种方法获得更多的LINQ,您可以复制到您的项目中。

这可能会奏效。这不是最简洁的代码,但对我来说似乎非常可读。它使用字符串连接,因为对于短字符串,如路径或URL,它比任何替代方法都要快

编辑:修复并测试。

var query = path.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries)
    .Aggregate(new List<string>(), (memo, segment) => {

        memo.Add(memo.DefaultIfEmpty("").Last() + "/" + segment);

        return memo;

    }).Aggregate(new List<string>(), (memo, p) => {

        memo.Add(p);
        memo.Add(p + "/default");

        return memo;

    });
var query=path.Split(新[]{'/},StringSplitOptions.RemoveEmptyEntries)
.Aggregate(新列表(),(备忘录,段)=>{
memo.Add(memo.DefaultIfEmpty(“”.Last()+“/”+段);
返回备忘录;
}).Aggregate(新列表(),(备忘录,p)=>{
备忘录.添加(p);
备注:添加(p+“/默认值”);
返回备忘录;
});

使用
Path.combined
而不是
string.Format(“{0}/{1}”
生成您提供的示例输出的输入是什么?输入将是值
“/Path/to/file”
。我还更新了这个问题。很好的解决方案。您可以键入
Path.Split(新[]{Path.directoryseportorchar},StringSplitOptions.RemoveEmptyEntries)
使其在Unix和Windows计算机上都能工作。请使用
Path.directorySpeparatorChar
而不是
“/”同时也考虑<代码>路径。concatenation@IlyaIvanov好的方面。我还试图找到一种不使用
temp
变量的方法。欢迎提供任何建议。@IlyaIvanov,因为输入是一个URI段,而不是文件系统路径。我不认为
path.directoryseportorchar
app谎言。由于separatos不依赖于平台,我认为硬编码是可以接受的。@Bobson我不熟悉这种方法。如果你是说
聚合
,那将不起作用,因为它只返回一个结果,而不是一个集合。@DStanley-你是对的,我记错了。对此很抱歉。谢谢!需要注意的是
virtualPath
值实际上是一个虚拟值,因此在所有平台上,分隔符字符始终相同“/”(如果我理解正确)@daptia在这种情况下,请忽略最后一条评论。你为什么要这样做而不是使用
foreach
?太棒了!!这看起来就像我在寻找的。我真的很喜欢这种方法。我会尝试一下,看看它是如何工作的。