LINQ를 사용하여 현을 연결합니다
-
03-07-2019 - |
문제
구식을 쓰는 가장 효율적인 방법은 무엇입니까?
StringBuilder sb = new StringBuilder();
if (strings.Count > 0)
{
foreach (string s in strings)
{
sb.Append(s + ", ");
}
sb.Remove(sb.Length - 2, 2);
}
return sb.ToString();
... LINQ에서?
해결책
이 답변은 LINQ의 사용법을 보여줍니다 (Aggregate
) 질문에 요청 된대로 일상적인 사용을위한 것이 아닙니다. 이것은 사용되지 않기 때문에 StringBuilder
매우 긴 시퀀스의 끔찍한 성능을 가질 것입니다. 정기적 인 코드 사용 String.Join
다른 쪽에서 볼 수 있듯이 대답
다음과 같은 집계 쿼리를 사용하십시오.
string[] words = { "one", "two", "three" };
var res = words.Aggregate(
"", // start with empty string to handle empty list case.
(current, next) => current + ", " + next);
Console.WriteLine(res);
이 출력 :
one, two, three
집계는 값을 모으고 스칼라 값을 반환하는 함수입니다. T-SQL의 예로는 Min, Max 및 Sum이 포함됩니다. VB와 C#은 모두 집계를 지원합니다. VB 및 C#은 모두 확장 방법으로 응집체를 지원합니다. 도트 계약을 사용하면 단순히 메소드를 호출합니다. ienumerable 물체.
집계 쿼리는 즉시 실행됩니다.
추가 정보 - MSDN : 집계 쿼리
정말로 사용하고 싶다면 Aggregate
변형 사용을 사용하십시오 StringBuilder
의견에 제안 CodemonKeyking 이것은 규칙과 거의 같은 코드입니다 String.Join
많은 객체에 대한 우수한 성능 포함 :
var res = words.Aggregate(
new StringBuilder(),
(current, next) => current.Append(current.Length == 0? "" : ", ").Append(next))
.ToString();
다른 팁
return string.Join(", ", strings.ToArray());
.NET 4에는 새로운 것이 있습니다 초과 적재 ~을 위한 string.Join
그것은 받아들입니다 IEnumerable<string>
. 코드는 다음과 같습니다.
return string.Join(", ", strings);
LINQ를 사용하는 이유는 무엇입니까?
string[] s = {"foo", "bar", "baz"};
Console.WriteLine(String.Join(", ", s));
그것은 완벽하게 작동하고 어떤 것을 받아들입니다 IEnumerable<string>
내가 기억하기로는. 필요 없음 Aggregate
여기에 훨씬 느린 것이 무엇이든.
집계 연장 방법을 살펴 보셨습니까?
var sa = (new[] { "yabba", "dabba", "doo" }).Aggregate((a,b) => a + "," + b);
내 코드의 실제 예 :
return selected.Select(query => query.Name).Aggregate((a, b) => a + ", " + b);
쿼리는 문자열 인 이름 속성이있는 객체이며 선택한 목록의 모든 쿼리의 이름을 쉼표로 분리하고 싶습니다.
당신이 사용할 수있는 StringBuilder
안에 Aggregate
:
List<string> strings = new List<string>() { "one", "two", "three" };
StringBuilder sb = strings
.Select(s => s)
.Aggregate(new StringBuilder(), (ag, n) => ag.Append(n).Append(", "));
if (sb.Length > 0) { sb.Remove(sb.Length - 2, 2); }
Console.WriteLine(sb.ToString());
(그만큼 Select
더 많은 linq 일을 할 수 있다는 것을 보여주기 위해 거기에 있습니다.)
다음은 다른 답변과 해결 된 문제를 살펴본 후 해결 한 Join/LINQ 접근 방식입니다. 비슷한 질문에서 (즉, 골재 및 컨텍스트는 0 요소로 실패합니다).
string Result = String.Join(",", split.Select(s => s.Name));
또는 (if s
문자열이 아닙니다)
string Result = String.Join(",", split.Select(s => s.ToString()));
- 단순한
- 읽고 이해하기 쉽습니다
- 일반 요소에 대해 작동합니다
- 객체 또는 객체 속성을 사용할 수 있습니다
- 0 길이 요소의 경우를 처리합니다
- 추가 LINQ 필터링과 함께 사용할 수 있습니다
- 잘 수행합니다 (적어도 내 경험에서)
- 추가 객체의 (수동) 생성이 필요하지 않습니다 (예 :
StringBuilder
) 구현
그리고 물론 가입은 때때로 다른 접근법에 몰래 들어가는 성가신 최종 쉼표를 처리합니다.for
, foreach
), 이것이 내가 처음에 LINQ 솔루션을 찾고 있었던 이유입니다.
StringBuilder 대 3000 개 이상의 요소를 선택 및 집계 케이스에 대한 빠른 성능 데이터 :
단위 테스트 - 지속 시간 (초)
LINQ_STRINGBUILDER -0.0036644
linq_select.aggregate -1.8012535
[TestMethod()]
public void LINQ_StringBuilder()
{
IList<int> ints = new List<int>();
for (int i = 0; i < 3000;i++ )
{
ints.Add(i);
}
StringBuilder idString = new StringBuilder();
foreach (int id in ints)
{
idString.Append(id + ", ");
}
}
[TestMethod()]
public void LINQ_SELECT()
{
IList<int> ints = new List<int>();
for (int i = 0; i < 3000; i++)
{
ints.Add(i);
}
string ids = ints.Select(query => query.ToString())
.Aggregate((a, b) => a + ", " + b);
}
나는 항상 확장 방법을 사용합니다.
public static string JoinAsString<T>(this IEnumerable<T> input, string seperator)
{
var ar = input.Select(i => i.ToString()).ToArray();
return string.Join(seperator, ar);
}
에 의해 '슈퍼 쿨 LINQ 방식'당신은 LINQ가 확장 방법을 사용하여 기능적 프로그래밍을 훨씬 더 맛있게 만드는 방식에 대해 이야기하고있을 것입니다. 내 말은, 기능을 둥지 (하나는 다른 하나) 대신 시각적으로 선형적인 방식으로 (다른 한편으로는) 시각적으로 선형적인 방식으로 묶을 수 있도록하는 구문 설탕을 의미합니다. 예를 들어:
int totalEven = Enumerable.Sum(Enumerable.Where(myInts, i => i % 2 == 0));
다음과 같이 쓸 수 있습니다.
int totalEven = myInts.Where(i => i % 2 == 0).Sum();
두 번째 예제가 어떻게 읽기 쉬운 지 알 수 있습니다. 덜 들여 쓰기 문제 또는 리시 표현의 끝에 나타나는 파렌을 닫습니다.
다른 많은 대답은 String.Join
읽는 가장 빠르거나 단순하기 때문에가는 길입니다. 하지만 당신이 내 해석을하면 '슈퍼 쿨 LINQ 방식'그러면 대답은 사용하는 것입니다 String.Join
그러나 LINQ 스타일 확장 방법으로 래핑하여 기능을 시각적으로 즐거운 방식으로 체인 할 수 있습니다. 그래서 당신이 쓰고 싶다면 sa.Concatenate(", ")
당신은 다음과 같은 것을 만들어야합니다.
public static class EnumerableStringExtensions
{
public static string Concatenate(this IEnumerable<string> strings, string separator)
{
return String.Join(separator, strings);
}
}
이것은 직접 통화만큼 성능이있는 코드 (적어도 알고리즘 복잡성 측면에서)를 제공하며 경우에 따라 블록의 다른 코드가 사슬 된 기능 스타일을 사용하는 경우 (컨텍스트에 따라) 코드를 더 읽기 쉽게 만들 수 있습니다. .
이것에 대한 다양한 대안이 있습니다 이전 질문 - 정수 배열을 소스로 타겟팅했지만 일반화 된 답변을 받았습니다.
여기에서는 순수한 LINQ를 단일 표현식으로 사용합니다.
static string StringJoin(string sep, IEnumerable<string> strings) {
return strings
.Skip(1)
.Aggregate(
new StringBuilder().Append(strings.FirstOrDefault() ?? ""),
(sb, x) => sb.Append(sep).Append(x));
}
그리고 그 꽤 망할 빨리!
나는 약간의 속임수를 쓰고 이것에 대한 새로운 대답을 버릴 것입니다. 이에 대한 새로운 답변을 던질 것입니다. 이에 대한 새로운 대답을 던질 것입니다. 이에 대한 새로운 답변을 던질 것입니다.
그래서 당신은 이것을 한 줄에 할 수 있습니다 :
List<string> strings = new List<string>() { "one", "two", "three" };
string concat = strings
.Aggregate(new StringBuilder("\a"),
(current, next) => current.Append(", ").Append(next))
.ToString()
.Replace("\a, ",string.Empty);
편집하다: 빈 열거 가능한 먼저 확인하거나 추가 할 수 있습니다. .Replace("\a",string.Empty);
표현의 끝까지. 너무 똑똑해 지려고했을 것 같아요.
@a.friend의 답변은 약간 더 성능이있을 수 있습니다. 나는 제거에 비해 후드 아래에서 어떻게 교체하는지 잘 모르겠습니다. 유일한 다른 경고는 당신이 a로 끝나는 줄을 동의하고 싶다면 당신은 당신의 분리기를 잃을 것입니다 ... 나는 그럴 것 같지 않습니다. 그것이 당신이 가진 경우라면 다른 멋진 캐릭터 에서 고르다.
LINQ를 결합 할 수 있습니다 string.join()
상당히 효과적으로. 여기서 나는 문자열에서 항목을 제거하고 있습니다. 이 작업을 수행하는 더 좋은 방법이 있지만 여기에 다음과 같습니다.
filterset = String.Join(",",
filterset.Split(',')
.Where(f => mycomplicatedMatch(f,paramToMatch))
);
여기에 많은 선택이 있습니다. LINQ와 StringBuilder를 사용할 수 있으므로 성능도 마찬가지입니다.
StringBuilder builder = new StringBuilder();
List<string> MyList = new List<string>() {"one","two","three"};
MyList.ForEach(w => builder.Append(builder.Length > 0 ? ", " + w : w));
return builder.ToString();
LINQ를 사용하여 IIS 로그 파일을 구문 분석 할 때 다음과 같은 빠르고 더러운 일을했는데, 2 백만 줄을 시도 할 때 메모리 오류가 발생했지만 1 백만 줄 (15 초) @ 1 백만 줄 (15 초)이 작동했습니다.
static void Main(string[] args)
{
Debug.WriteLine(DateTime.Now.ToString() + " entering main");
// USED THIS DOS COMMAND TO GET ALL THE DAILY FILES INTO A SINGLE FILE: copy *.log target.log
string[] lines = File.ReadAllLines(@"C:\Log File Analysis\12-8 E5.log");
Debug.WriteLine(lines.Count().ToString());
string[] a = lines.Where(x => !x.StartsWith("#Software:") &&
!x.StartsWith("#Version:") &&
!x.StartsWith("#Date:") &&
!x.StartsWith("#Fields:") &&
!x.Contains("_vti_") &&
!x.Contains("/c$") &&
!x.Contains("/favicon.ico") &&
!x.Contains("/ - 80")
).ToArray();
Debug.WriteLine(a.Count().ToString());
string[] b = a
.Select(l => l.Split(' '))
.Select(words => string.Join(",", words))
.ToArray()
;
System.IO.File.WriteAllLines(@"C:\Log File Analysis\12-8 E5.csv", b);
Debug.WriteLine(DateTime.Now.ToString() + " leaving main");
}
내가 LINQ를 사용한 진짜 이유는 이전에 필요한 고유 한 ()에 대한 것이 었습니다.
string[] b = a
.Select(l => l.Split(' '))
.Where(l => l.Length > 11)
.Select(words => string.Format("{0},{1}",
words[6].ToUpper(), // virtual dir / service
words[10]) // client ip
).Distinct().ToArray()
;
나는 얼마 전에 이것에 대해 블로그를 작성했다.
http://ondevelopment.blogspot.com/2009/02/string-concatenation-made-easy.html
블로그 게시물에서 ienumerable에서 작동하고 ConcateNate로 명명 된 확장 방법을 구현하는 방법을 설명하면 다음과 같은 내용을 쓸 수 있습니다.
var sequence = new string[] { "foo", "bar" };
string result = sequence.Concatenate();
또는 더 정교한 것들 :
var methodNames = typeof(IFoo).GetMethods().Select(x => x.Name);
string result = methodNames.Concatenate(", ");