ความแตกต่างของ LINQ () ในคุณสมบัติเฉพาะ


1094

ฉันกำลังเล่นกับ LINQ เพื่อเรียนรู้เกี่ยวกับเรื่องนี้ แต่ฉันไม่สามารถหาวิธีใช้Distinctเมื่อฉันไม่มีรายการแบบง่าย (รายการจำนวนเต็มง่าย ๆ ค่อนข้างง่ายที่จะทำนี่ไม่ใช่คำถาม) ถ้าสิ่งที่ฉันต้องการที่จะใช้ที่แตกต่างในรายชื่อของวัตถุในหนึ่งหรืออื่น ๆ อีกมากมายคุณสมบัติของวัตถุหรือไม่

ตัวอย่าง: หากวัตถุอยู่กับทรัพย์สินPerson Idฉันจะรับบุคคลทั้งหมดและใช้Distinctกับพวกเขาด้วยคุณสมบัติIdของวัตถุได้อย่างไร

Person1: Id=1, Name="Test1"
Person2: Id=1, Name="Test1"
Person3: Id=2, Name="Test2"

ฉันจะได้รับเพียงแค่Person1และได้Person3อย่างไร เป็นไปได้ไหม

ถ้ามันเป็นไปไม่ได้กับ LINQ สิ่งที่จะเป็นวิธีที่ดีที่สุดในการมีรายการPersonขึ้นอยู่กับคุณสมบัติบางอย่างใน. NET 3.5

คำตอบ:


1246

แก้ไข : นี่เป็นส่วนหนึ่งของMoreLINQ

สิ่งที่คุณต้องการคือ "ชัดเจนโดย" อย่างมีประสิทธิภาพ ฉันไม่เชื่อว่ามันเป็นส่วนหนึ่งของ LINQ ตามที่ตั้งแม้ว่ามันจะค่อนข้างง่ายต่อการเขียน:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (seenKeys.Add(keySelector(element)))
        {
            yield return element;
        }
    }
}

ดังนั้นเพื่อค้นหาค่าที่แตกต่างโดยใช้Idคุณสมบัติคุณสามารถใช้:

var query = people.DistinctBy(p => p.Id);

และใช้งานคุณสมบัติหลายรายการคุณสามารถใช้ชนิดที่ไม่ระบุชื่อซึ่งใช้ความเท่าเทียมกันอย่างเหมาะสม:

var query = people.DistinctBy(p => new { p.Id, p.Name });

ยังไม่ทดลอง แต่ควรใช้งานได้ (และอย่างน้อยก็ตอนนี้คอมไพล์แล้ว)

มันถือว่าตัวเปรียบเทียบเริ่มต้นสำหรับคีย์แม้ว่า - หากคุณต้องการส่งผ่านตัวเปรียบเทียบความเท่าเทียมกันเพียงแค่ส่งผ่านไปยังตัวHashSetสร้าง


7
แหล่งที่มาของ DistinctBy: code.google.com/p/morelinq/source/browse/MoreLinq/DistinctBy.cs
Contango

1
@ ashes999: ฉันไม่แน่ใจว่าคุณหมายถึงอะไร รหัสนี้มีอยู่ในคำตอบและในห้องสมุด - ขึ้นอยู่กับว่าคุณยินดีที่จะพึ่งพาหรือไม่
Jon Skeet

10
@ ashes999: หากคุณทำสิ่งนี้ในที่เดียวแน่นอนว่าการใช้GroupByนั้นง่ายกว่า หากคุณต้องการมากกว่าหนึ่งที่มันสะอาดกว่า (IMO) เพื่อสรุปความตั้งใจ
Jon Skeet

5
@ Matewewhhited: เนื่องจากไม่มีการเอ่ยถึงIQueryable<T>ที่นี่ฉันไม่เห็นว่ามันเกี่ยวข้องกันอย่างไร ผมเห็นว่าเรื่องนี้จะไม่เหมาะสำหรับ EF ฯลฯ แต่ภายใน LINQ กับวัตถุที่ฉันคิดว่ามันมากขึ้นGroupByเหมาะกว่า บริบทของคำถามเป็นสิ่งสำคัญเสมอ
Jon Skeet

7
โครงการย้ายไปที่ github นี่คือรหัส DistinctBy: github.com/morelinq/MoreLINQ/blob/master/MoreLinq/DistinctBy.cs
Phate01

1858

หากฉันต้องการที่จะได้รับรายชื่อที่แตกต่างกันขึ้นอยู่กับหนึ่งหรืออื่น ๆ อีกมากมายคุณสมบัติ?

! ง่าย คุณต้องการจัดกลุ่มพวกเขาและเลือกผู้ชนะจากกลุ่ม

List<Person> distinctPeople = allPeople
  .GroupBy(p => p.PersonId)
  .Select(g => g.First())
  .ToList();

หากคุณต้องการกำหนดกลุ่มในคุณสมบัติหลาย ๆ นี่คือวิธี:

List<Person> distinctPeople = allPeople
  .GroupBy(p => new {p.PersonId, p.FavoriteColor} )
  .Select(g => g.First())
  .ToList();

1
@ErenErsonmez แน่นอน ด้วยรหัสที่โพสต์ของฉันหากต้องการการดำเนินการรอการตัดบัญชีให้ปล่อยการเรียก ToList
เอมี่บี

5
คำตอบที่ดีมาก! Realllllly ช่วยฉันใน Linq-to-Entities จากมุมมอง sql ซึ่งฉันไม่สามารถปรับเปลี่ยนมุมมองได้ ฉันต้องการใช้ FirstOrDefault () มากกว่า First () - ทั้งหมดนั้นดี
Alex KeySmith

8
ฉันลองแล้วและควรเปลี่ยนเป็น Select (g => g.FirstOrDefault ())

26
@ChocapicSz Nope ทั้งสองSingle()และSingleOrDefault()แต่ละครั้งเมื่อแหล่งที่มามีมากกว่าหนึ่งรายการ ในการดำเนินการนี้เราคาดว่าความเป็นไปได้ที่แต่ละกลุ่มอาจมีมากกว่าหนึ่งรายการ สำหรับเรื่องที่First()เป็นที่ต้องการมากกว่าFirstOrDefault()เพราะแต่ละกลุ่มต้องมีสมาชิกอย่างน้อยหนึ่ง .... ถ้าคุณกำลังใช้ EntityFramework FirstOrDefault()ซึ่งไม่สามารถคิดออกว่าแต่ละกลุ่มมีอย่างน้อยหนึ่งสมาชิกและความต้องการ
เอมี่ B

2
ดูเหมือนว่าจะไม่ได้รับการสนับสนุนใน EF Core ในปัจจุบันแม้จะใช้FirstOrDefault() github.com/dotnet/efcore/issues/12088ฉันอยู่ที่ 3.1 และฉันได้รับข้อผิดพลาด "ไม่สามารถแปล"
Collin M. Barrett

78

ใช้:

List<Person> pList = new List<Person>();
/* Fill list */

var result = pList.Where(p => p.Name != null).GroupBy(p => p.Id).Select(grp => grp.FirstOrDefault());

whereจะช่วยให้คุณกรองรายการ (อาจจะซับซ้อนมากขึ้น) และgroupbyและselectดำเนินการฟังก์ชันที่แตกต่างกัน


1
สมบูรณ์แบบและทำงานได้โดยไม่ต้องขยาย Linq หรือใช้การพึ่งพาอื่น
DavidScherer

77

คุณสามารถใช้ไวยากรณ์คิวรีได้ถ้าคุณต้องการให้มันเหมือนกับ LINQ ทั้งหมด:

var uniquePeople = from p in people
                   group p by new {p.ID} //or group by new {p.ID, p.Name, p.Whatever}
                   into mygroup
                   select mygroup.FirstOrDefault();

4
อืมความคิดของฉันเป็นทั้งไวยากรณ์คิวรีและไวยากรณ์ API ได้อย่างคล่องแคล่วเหมือนกับ LINQ เหมือนกันและเป็นเพียงการตั้งค่าตามที่คนใช้ ตัวฉันเองชอบ API ที่คล่องแคล่วดังนั้นฉันจะพิจารณาว่ามีลิงค์มากกว่านั้น แต่ฉันเดาว่ามันเป็นอัตนัย
Max Carroll

LINQ-Like ไม่มีส่วนเกี่ยวข้องกับการตั้งค่าการเป็น "LINQ-like" จะทำอย่างไรกับการมองเหมือนภาษาแบบสอบถามที่แตกต่างกันซึ่งถูกฝังลงใน C # ฉันชอบอินเทอร์เฟซที่คล่องแคล่วซึ่งมาจากสตรีม java แต่ไม่ใช่ LINQ-Like
Ryan The Leach

ยอดเยี่ยม !! คุณคือฮีโร่ของฉัน!
Farzin Kanzi

63

ฉันคิดว่ามันเพียงพอ:

list.Select(s => s.MyField).Distinct();

43
ถ้าเขาต้องการวัตถุคืนเต็มของเขาไม่ใช่แค่สนามนั้น?
Festim Cahani

1
วัตถุอะไรของวัตถุหลายอย่างที่มีค่าคุณสมบัติเหมือนกัน?
donRumatta

40

โซลูชันกลุ่มแรกตามเขตข้อมูลของคุณจากนั้นเลือกรายการค่าเริ่มต้นแรก

    List<Person> distinctPeople = allPeople
   .GroupBy(p => p.PersonId)
   .Select(g => g.FirstOrDefault())
   .ToList();

26

Linq.ToLookup()คุณสามารถทำเช่นนี้กับมาตรฐาน สิ่งนี้จะสร้างชุดของค่าสำหรับแต่ละคีย์ที่ไม่ซ้ำกัน เพียงเลือกรายการแรกในคอลเล็กชัน

Persons.ToLookup(p => p.Id).Select(coll => coll.First());

17

รหัสต่อไปนี้เป็นหน้าที่เทียบเท่ากับคำตอบของจอนสกีต

ทดสอบกับ. NET 4.5 ควรทำงานกับ LINQ รุ่นก่อนหน้าใด ๆ

public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
  this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
  HashSet<TKey> seenKeys = new HashSet<TKey>();
  return source.Where(element => seenKeys.Add(keySelector(element)));
}

Incidentially ตรวจสอบเวอร์ชันล่าสุดจอนสกีตของ DistinctBy.cs ใน Google Code


3
สิ่งนี้ทำให้ฉัน "ลำดับไม่มีข้อผิดพลาดค่า" แต่คำตอบของ Skeet สร้างผลลัพธ์ที่ถูกต้อง
จะมีอะไรดีๆใน

10

ฉันได้เขียนบทความที่อธิบายถึงวิธีการขยายฟังก์ชั่นที่แตกต่างเพื่อให้คุณสามารถทำดังนี้:

var people = new List<Person>();

people.Add(new Person(1, "a", "b"));
people.Add(new Person(2, "c", "d"));
people.Add(new Person(1, "a", "b"));

foreach (var person in people.Distinct(p => p.ID))
    // Do stuff with unique list here.

นี่คือบทความ: การขยาย LINQ - การระบุคุณสมบัติในฟังก์ชันที่แตกต่าง


3
บทความของคุณมีข้อผิดพลาดควรมี <T> หลัง Distinct: public static IEnumerable <T> Distinct (นี่ ... นอกจากนี้ยังไม่ดูเหมือนว่าจะใช้งานได้ (อย่างดี) ในอีกคุณสมบัติหนึ่งนั่นคือการรวมกันของแรก และนามสกุล
row1

2
+1 ข้อผิดพลาดเล็ก ๆ น้อย ๆ นั้นไม่เพียงพอสำหรับ downvote นั่นมันงี่เง่าที่เรียกว่าพิมพ์ผิดบ่อยครั้ง และฉันยังไม่เห็นฟังก์ชั่นทั่วไปที่จะใช้งานได้กับคุณสมบัติจำนวนเท่าใดก็ได้! ฉันหวังว่า downvoter downvote ทุกคำตอบอื่น ๆ ในหัวข้อนี้เช่นกัน แต่เดี๋ยวก่อนประเภทที่สองคือวัตถุ? ฉันคัดค้าน!
nawfal

4
ลิงก์ของคุณเสีย
Tom Lint

7

ส่วนตัวผมใช้คลาสต่อไปนี้:

public class LambdaEqualityComparer<TSource, TDest> : 
    IEqualityComparer<TSource>
{
    private Func<TSource, TDest> _selector;

    public LambdaEqualityComparer(Func<TSource, TDest> selector)
    {
        _selector = selector;
    }

    public bool Equals(TSource obj, TSource other)
    {
        return _selector(obj).Equals(_selector(other));
    }

    public int GetHashCode(TSource obj)
    {
        return _selector(obj).GetHashCode();
    }
}

จากนั้นวิธีการขยาย:

public static IEnumerable<TSource> Distinct<TSource, TCompare>(
    this IEnumerable<TSource> source, Func<TSource, TCompare> selector)
{
    return source.Distinct(new LambdaEqualityComparer<TSource, TCompare>(selector));
}

ในที่สุดการใช้งานที่ตั้งใจ:

var dates = new List<DateTime>() { /* ... */ }
var distinctYears = dates.Distinct(date => date.Year);

ประโยชน์ที่ผมพบว่าใช้วิธีนี้คือเรื่องการใช้งานของLambdaEqualityComparerชั้นเรียนสำหรับวิธีการอื่น ๆ IEqualityComparerที่ยอมรับ (โอ้และฉันปล่อยให้yieldสิ่งต่าง ๆ กับการใช้งาน LINQ ดั้งเดิม ... )


5

ในกรณีที่คุณจำเป็นต้องมีวิธีการที่แตกต่างกันเกี่ยวกับคุณสมบัติหลายคุณสามารถตรวจสอบของฉันPowerfulExtensionsห้องสมุด ขณะนี้มันอยู่ในขั้นตอนที่ยังเด็กมาก แต่คุณสามารถใช้วิธีต่างๆเช่น Distinct, Union, Intersect, ยกเว้นคุณสมบัติจำนวนเท่าใดก็ได้

นี่คือวิธีที่คุณใช้:

using PowerfulExtensions.Linq;
...
var distinct = myArray.Distinct(x => x.A, x => x.B);

5

เมื่อเราเผชิญกับงานดังกล่าวในโครงการของเราเราได้กำหนด API ขนาดเล็กเพื่อเขียนเครื่องมือเปรียบเทียบ

ดังนั้นกรณีการใช้งานจึงเป็นเช่นนี้:

var wordComparer = KeyEqualityComparer.Null<Word>().
    ThenBy(item => item.Text).
    ThenBy(item => item.LangID);
...
source.Select(...).Distinct(wordComparer);

และ API เองก็มีลักษณะดังนี้:

using System;
using System.Collections;
using System.Collections.Generic;

public static class KeyEqualityComparer
{
    public static IEqualityComparer<T> Null<T>()
    {
        return null;
    }

    public static IEqualityComparer<T> EqualityComparerBy<T, K>(
        this IEnumerable<T> source,
        Func<T, K> keyFunc)
    {
        return new KeyEqualityComparer<T, K>(keyFunc);
    }

    public static KeyEqualityComparer<T, K> ThenBy<T, K>(
        this IEqualityComparer<T> equalityComparer,
        Func<T, K> keyFunc)
    {
        return new KeyEqualityComparer<T, K>(keyFunc, equalityComparer);
    }
}

public struct KeyEqualityComparer<T, K>: IEqualityComparer<T>
{
    public KeyEqualityComparer(
        Func<T, K> keyFunc,
        IEqualityComparer<T> equalityComparer = null)
    {
        KeyFunc = keyFunc;
        EqualityComparer = equalityComparer;
    }

    public bool Equals(T x, T y)
    {
        return ((EqualityComparer == null) || EqualityComparer.Equals(x, y)) &&
                EqualityComparer<K>.Default.Equals(KeyFunc(x), KeyFunc(y));
    }

    public int GetHashCode(T obj)
    {
        var hash = EqualityComparer<K>.Default.GetHashCode(KeyFunc(obj));

        if (EqualityComparer != null)
        {
            var hash2 = EqualityComparer.GetHashCode(obj);

            hash ^= (hash2 << 5) + hash2;
        }

        return hash;
    }

    public readonly Func<T, K> KeyFunc;
    public readonly IEqualityComparer<T> EqualityComparer;
}

รายละเอียดเพิ่มเติมได้ในเว็บไซต์ของเรา: IEqualityComparer ใน LINQ


5

คุณสามารถใช้ DistinctBy () เพื่อรับระเบียน Distinct ตามคุณสมบัติวัตถุ เพียงเพิ่มคำสั่งต่อไปนี้ก่อนที่จะใช้:

ใช้ Microsoft.Ajax.Utilities;

แล้วใช้มันเหมือนดังต่อไปนี้:

var listToReturn = responseList.DistinctBy(x => x.Index).ToList();

โดยที่ 'ดัชนี' เป็นคุณสมบัติที่ฉันต้องการให้ข้อมูลชัดเจน


4

คุณสามารถทำได้ (แม้ว่าจะไม่เร็วเกินไป) เช่น:

people.Where(p => !people.Any(q => (p != q && p.Id == q.Id)));

นั่นคือ "เลือกทุกคนที่ไม่มีบุคคลอื่นในรายการที่มี ID เดียวกัน"

ในใจของคุณในตัวอย่างที่จะเลือกคนที่ 3 ฉันไม่แน่ใจว่าจะบอกสิ่งที่คุณต้องการออกจากสองก่อนหน้านี้


4

หากคุณไม่ต้องการเพิ่มไลบรารี่ MoreLinq ลงในโครงการของคุณเพื่อรับDistinctByฟังก์ชั่นการใช้งานคุณสามารถรับผลลัพธ์สุดท้ายที่เหมือนกันโดยใช้Distinctเมธอดoverload ของ Linq ซึ่งIEqualityComparerขัดแย้งกัน

คุณเริ่มต้นด้วยการสร้างคลาสเครื่องมือเปรียบเทียบความเท่าเทียมกันทั่วไปที่กำหนดเองที่ใช้ไวยากรณ์แลมบ์ดาเพื่อทำการเปรียบเทียบแบบกำหนดเองของคลาสทั่วไปสองอินสแตนซ์:

public class CustomEqualityComparer<T> : IEqualityComparer<T>
{
    Func<T, T, bool> _comparison;
    Func<T, int> _hashCodeFactory;

    public CustomEqualityComparer(Func<T, T, bool> comparison, Func<T, int> hashCodeFactory)
    {
        _comparison = comparison;
        _hashCodeFactory = hashCodeFactory;
    }

    public bool Equals(T x, T y)
    {
        return _comparison(x, y);
    }

    public int GetHashCode(T obj)
    {
        return _hashCodeFactory(obj);
    }
}

จากนั้นในรหัสหลักของคุณคุณใช้มันเพื่อ:

Func<Person, Person, bool> areEqual = (p1, p2) => int.Equals(p1.Id, p2.Id);

Func<Person, int> getHashCode = (p) => p.Id.GetHashCode();

var query = people.Distinct(new CustomEqualityComparer<Person>(areEqual, getHashCode));

Voila! :)

ข้างต้นจะถือว่าสิ่งต่อไปนี้:

  • คุณสมบัติPerson.Idเป็นประเภทint
  • peopleคอลเลกชันไม่ได้มีองค์ประกอบ null ใด ๆ

หากการเก็บรวบรวมอาจมีค่า Null ให้ทำการเขียน lambdas ใหม่เพื่อตรวจสอบค่า Null เช่น:

Func<Person, Person, bool> areEqual = (p1, p2) => 
{
    return (p1 != null && p2 != null) ? int.Equals(p1.Id, p2.Id) : false;
};

แก้ไข

วิธีนี้คล้ายกับคำตอบใน Vladimir Nesterovsky แต่ง่ายกว่า

นอกจากนี้ยังคล้ายกับคำตอบของ Joel แต่อนุญาตให้ใช้ตรรกะเปรียบเทียบที่ซับซ้อนที่เกี่ยวข้องกับคุณสมบัติหลายอย่าง

อย่างไรก็ตามหากวัตถุของคุณสามารถแตกต่างกันไปตามIdนั้นผู้ใช้รายอื่นให้คำตอบที่ถูกต้องว่าสิ่งที่คุณต้องทำคือแทนที่การใช้งานเริ่มต้นของGetHashCode()และEquals()ในPersonชั้นเรียนของคุณแล้วใช้วิธีการนอกกรอบDistinct()ของ Linq เพื่อกรอง ทำซ้ำใด ๆ


ฉันต้องการที่จะได้รับเฉพาะรายการที่ไม่ซ้ำกันใน dictonary คุณสามารถช่วยฉันใช้รหัสนี้ถ้า TempDT IsNot ไม่มีอะไรแล้ว m_ConcurrentScriptDictionary = TempDT.AsEnumerable.ToDictionary (Function (x) x.SafeField (fldClusterId, NULL_ID_VALUE), ฟังก์ชั่น y.SafeField (fldParamValue11, NULL_ID_VALUE))
RSB

2

วิธีที่ดีที่สุดในการทำเช่นนี้ที่จะเข้ากันได้กับ. NET รุ่นอื่นคือการแทนที่ Equals และ GetHash เพื่อจัดการสิ่งนี้ (ดูคำถาม Stack Overflow รหัสนี้จะส่งกลับค่าที่แตกต่างกันอย่างไรก็ตามสิ่งที่ฉันต้องการคือ ประเภทที่ไม่ระบุชื่อ ) แต่ถ้าคุณต้องการบางสิ่งที่เป็นรหัสทั่วไปในรหัสของคุณโซลูชันในบทความนี้ยอดเยี่ยม


1
List<Person>lst=new List<Person>
        var result1 = lst.OrderByDescending(a => a.ID).Select(a =>new Player {ID=a.ID,Name=a.Name} ).Distinct();

คุณหมายถึงการSelect() new Personแทนnew Player? ความจริงที่ว่าคุณกำลังสั่งซื้อโดยIDไม่แจ้งDistinct()ให้ใช้คุณสมบัตินั้นในการพิจารณาความเป็นเอกลักษณ์ แต่อย่างใดดังนั้นสิ่งนี้จะไม่ทำงาน
BACON

1

แทนที่เท่ากับ (วัตถุ obj)และGetHashCode ()วิธีการ:

class Person
{
    public int Id { get; set; }
    public int Name { get; set; }

    public override bool Equals(object obj)
    {
        return ((Person)obj).Id == Id;
        // or: 
        // var o = (Person)obj;
        // return o.Id == Id && o.Name == Name;
    }
    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}

จากนั้นเพียงแค่โทร:

List<Person> distinctList = new[] { person1, person2, person3 }.Distinct().ToList();

อย่างไรก็ตาม GetHashCode () ควรจะสูงกว่า (หากนับชื่อด้วย) คำตอบนี้น่าจะดีที่สุดโดยความเห็นของฉัน ที่จริงแล้วการเก็บตรรกะเป้าหมายนั้นไม่จำเป็นต้องแทนที่ GetHashCode (), Equals () ก็เพียงพอแล้ว แต่ถ้าเราต้องการประสิทธิภาพเราต้องลบล้างมัน algs เปรียบเทียบทั้งหมดตรวจสอบแฮชก่อนและถ้าเท่ากันให้เรียก Equals ()
Oleg Skripnyak

นอกจากนี้ยังมีใน Equals () บรรทัดแรกควรเป็น "if (! (obj is Person)) return false" แต่วิธีปฏิบัติที่ดีที่สุดคือการใช้วัตถุแยกประเภทที่ถูกแยกประเภทเช่น "var o = obj เป็นบุคคลถ้า (o == null) กลับเท็จ" จากนั้นตรวจสอบความเท่าเทียมกันกับ o โดยไม่ต้องแคส
Oleg Skripnyak

1
การเอาชนะเท่าเทียมกันเช่นนี้ไม่ใช่ความคิดที่ดีเพราะอาจมีผลกระทบที่ไม่ตั้งใจสำหรับโปรแกรมเมอร์คนอื่น ๆ ที่คาดหวังความเท่าเทียมกันของบุคคลที่จะถูกกำหนดมากกว่าทรัพย์สินเดียว
B2K

0

คุณควรจะสามารถแทนที่ Equals ในบุคคลเพื่อทำ Equals on Person.id ได้ สิ่งนี้ควรจะส่งผลให้พฤติกรรมของคุณหลังจาก


-5

กรุณาลองด้วยรหัสด้านล่าง

var Item = GetAll().GroupBy(x => x .Id).ToList();

3
ยินดีต้อนรับคำตอบสั้น ๆ แต่ก็จะไม่ให้คุณค่ากับผู้ใช้หลังที่พยายามเข้าใจว่าเกิดอะไรขึ้นหลังปัญหา โปรดสละเวลาสักครู่เพื่ออธิบายว่าอะไรคือปัญหาที่แท้จริงที่ทำให้เกิดปัญหาและวิธีแก้ไข ขอบคุณ ~
ได้ยิน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.