data-structures - لماذا لا تحصل على java.util.Set(فهرس int)؟




collections (15)

أنا متأكد من أن هناك سببًا جيدًا ، ولكن هل يمكن لشخص ما أن يفسر سبب عدم حصول واجهة java.util.Set get(int Index) ، أو أي طريقة مشابهة get() ؟

يبدو أن المجموعات رائعة لوضع الأشياء ، ولكن لا يمكنني العثور على طريقة أنيقة لاسترداد عنصر واحد منه.

إذا كنت أعرف أنني أريد العنصر الأول ، set.iterator().next() استخدام set.iterator().next() ، ولكن بخلاف ذلك ، يبدو أنه يتوجب علي إرسال مجموعة إلى مصفوفة لاسترداد عنصر في فهرس معين؟

ما هي الطرق المناسبة لاسترداد البيانات من مجموعة؟ (بخلاف استخدام مكرر)

أنا متأكد من حقيقة أن استبعاده من واجهة برمجة التطبيقات يعني وجود سبب وجيه لعدم القيام بذلك - هل يمكن لأي شخص أن ينيرني؟

تحرير: بعض إجابات كبيرة للغاية هنا ، وقليل من قوله "المزيد من السياق". كان السيناريو المحدد هو اختبار dbUnit ، حيث يمكنني أن أؤكد بشكل معقول أن المجموعة التي تم إرجاعها من استعلام تحتوي على عنصر واحد فقط ، وكنت أحاول الوصول إلى هذا العنصر.

ومع ذلك ، فإن السؤال أكثر صلاحية بدون السيناريو ، لأنه لا يزال أكثر تركيزًا:

ما الفرق بين المجموعة والقائمة .

شكرا للجميع على إجابات رائعة أدناه.


Answers

هذا النوع من يؤدي إلى السؤال عندما يجب عليك استخدام مجموعة ومتى يجب عليك استخدام قائمة. عادة ، تذهب النصيحة:

  1. إذا كنت بحاجة إلى البيانات المطلوبة ، فاستخدم قائمة
  2. إذا كنت بحاجة إلى بيانات فريدة ، فاستخدم مجموعة
  3. إذا كنت بحاجة إلى كليهما ، فاستخدم إما: SortedSet (للبيانات المطلوبة بواسطة المقارنة) أو OrderedSet / UniqueList (للبيانات المطلوبة بواسطة الإدراج). لسوء الحظ ، لا يحتوي Java API بعد على OrderedSet / UniqueList.

والحالة الرابعة التي تظهر في كثير من الأحيان هي أنك لا تحتاج إلى أي منهما. في هذه الحالة سترى بعض المبرمجين يذهب مع القوائم وبعض مع مجموعات. أنا شخصياً أجد أنه من الضار جداً رؤية المجموعة كقائمة بدون طلب - لأنه في الحقيقة وحش آخر بأكمله. ما لم تكن بحاجة إلى أشياء مثل تفرد معين أو تعيين المساواة ، تفضل دائمًا القوائم.


هذا صحيح ، لا يتم ترتيب العنصر في المجموعة ، من خلال تعريف مجموعة المجموعة. لذلك لا يمكن الوصول إليها عن طريق فهرس.

ولكن لماذا لا نحصل على طريقة (كائن) ، وليس من خلال توفير المؤشر كمعلمة ، بل هو كائن مساو للشيء الذي نبحث عنه؟ وبهذه الطريقة ، يمكننا الوصول إلى بيانات العنصر داخل المجموعة ، فقط من خلال معرفة سماته المستخدمة بواسطة الطريقة المتساوية.


إذا كنت ستفعل الكثير من الوصول العشوائي عن طريق الفهرس في مجموعة ، يمكنك الحصول على عرض مصفوفة لعناصرها:

Object[] arrayView = mySet.toArray();
//do whatever you need with arrayView[i]

هناك نوعان من العيوب الرئيسية على الرغم من:

  1. إنها لا تتسم بالكفاءة في استخدام الذاكرة ، نظرًا لأنه يلزم إنشاء مصفوفة لمجموعة كاملة.
  2. إذا تم تعديل المجموعة ، يصبح العرض قديمًا.

في الواقع هذا سؤال متكرر عند كتابة تطبيقات JavaEE التي تستخدم التعيين Object-Relational (على سبيل المثال مع Hibernate) ؛ ومن جميع الأشخاص الذين أجابوا هنا ، كان أندرياس بيترسون هو الشخص الوحيد الذي فهم القضية الحقيقية وعرض الإجابة الصحيحة لها: جافا تفتقد إلى قائمة فريدة! (أو يمكنك أيضًا الاتصال به OrderedSet أو IndexedSet).

ذكر Maxwing حالة الاستخدام هذه (التي تحتاج فيها إلى بيانات مرتبة و فريدة) واقترح على SortedSet ، لكن هذا ليس ما يحتاجه Marty Pitt فعلاً.

هذا "IndexedSet" ليس هو نفسه لـ SortedSet - في SortedSet يتم فرز العناصر باستخدام المقارنة (أو باستخدام الطلب "الطبيعي" الخاص به).

ولكن بدلاً من ذلك ، يكون أقرب إلى LinkedHashSet (الذي اقترحه الآخرون أيضًا) ، أو أكثر إلى (AroundListSet) (لأنه غير موجود أيضًا) ، لأنه يضمن إرجاع العناصر بنفس الترتيب الذي تم إدخالها به.

لكن LinkedHashSet هو تطبيق ، وليس واجهة! ما هو مطلوب هو واجهة IndexedSet (أو ListSet ، أو OrderedSet ، أو UniqueList)! سيسمح هذا للمبرمج بتحديد أنه يحتاج إلى مجموعة من العناصر التي لها ترتيب معين وبدون تكرار ، ثم قم بتشكيله بأي تنفيذ (على سبيل المثال ، تنفيذ يوفره Hibernate).

نظرًا لأن JDK مفتوح المصدر ، فربما يتم تضمين هذه الواجهة أخيراً في Java 7 ...


للحصول على عنصر في مجموعة ، يمكنني استخدام لمتابعة واحد:

public T getElement(Set<T> set, T element) {
T result = null;
if (set instanceof TreeSet<?>) {
    T floor = ((TreeSet<T>) set).floor(element);
    if (floor != null && floor.equals(element))
    result = floor;
} else {
    boolean found = false;
    for (Iterator<T> it = set.iterator(); !found && it.hasNext();) {
    if (true) {
        T current = it.next();
        if (current.equals(element)) {
        result = current;
        found = true;
        }
    }
    }
}
return result;
}

لقد واجهت حالات كنت في الواقع أرغب في مجموعة مفرغة مع الوصول عبر الفهرس (أنا أتفق مع ملصقات أخرى أن الوصول إلى مجموعة لم يتم فرزها مع فهرس لا معنى له). مثال على ذلك هو شجرة حيث كنت أريد أن يتم فرز الأطفال ولم يسمح للأطفال المكررة.

كنت بحاجة إلى الوصول عبر الفهرس لعرضها ، وكانت سمات المجموعة مفيدة للتخلص بشكل فعال من التكرارات.

العثور على أي مجموعة مناسبة في مجموعات java.util أو google ، وجدت أنه من السهل تنفيذها بنفسي. الفكرة الأساسية هي لفك SortedSet وإنشاء قائمة عندما يكون الوصول عبر الفهرس مطلوبًا (ونسيان القائمة عند تغيير SortedSet). هذا بالطبع لا تعمل إلا بكفاءة عند تغيير SortedSet الملتفة والوصول إلى القائمة يتم فصل في عمر المجموعة. خلاف ذلك يتصرف مثل قائمة التي يتم فرزها في كثير من الأحيان ، أي بطيئة للغاية.

مع وجود أعداد كبيرة من الأطفال ، تحسن هذا الأداء كثيرًا على قائمة احتفظت بها من خلال Collections.sort.


وذلك لأن Set Only يضمن التفرد ، ولكنه لا يذكر شيئًا عن أنماط الوصول أو الاستخدام الأمثل. أي ، يمكن أن تكون مجموعة قائمة أو خريطة ، لكل منها خصائص استرجاع مختلفة جدًا.


السبب في أن واجهة Set لا تحتوي على استدعاء من نوع فهرس أو حتى شيء أكثر أساسية ، مثل first () أو last () ، لأنه عملية غامضة ، وبالتالي عملية خطيرة محتملة. إذا كانت إحدى الطرق تقوم بإرجاع مجموعة (Set) ، وقمت بالاتصال ، فقم بتعبير أول () طريقة ، ما هي النتيجة المتوقعة ، على اعتبار أن مجموعة عامة لا تقدم أي ضمانات بشأن الطلب؟ قد يختلف الكائن الناتج تمامًا بين كل استدعاء لهذه الطريقة ، أو قد لا يؤدي إلى تهدئتك وإدراكك إلى إحساس زائف بالأمان ، إلى أن تغير المكتبة التي تستخدمها التغييرات في التنفيذ وتجد الآن أن جميع فواصل الشفرة الخاصة بك لا يوجد سبب معين.

الاقتراحات حول الحلول المدرجة هنا جيدة. إذا كنت بحاجة إلى الوصول المفهرسة ، فاستخدم قائمة. كن حذرًا عند استخدام المتكررات أو إلى التسجيل باستخدام مجموعة عامة ، لأن (أ) لا يوجد ضمان على الطلب و (ب) لا يوجد ضمان بأن الترتيب لن يتغير مع الدعوات اللاحقة أو مع التطبيقات الأساسية المختلفة. إذا كنت تحتاج إلى شيء ما بين ، فإن SortedSet أو LinkedHashSet هو ما تريده.

/ / أنا أتمنى لو أن واجهة التعيين كانت تحتوي على عنصر الحصول على عشوائي على الرغم من ذلك.


لأن مجموعات ليس لديها ترتيب. تقوم بعض التطبيقات (خاصةً تلك التي تقوم بتنفيذ واجهة java.util.SortedSet ) ، ولكنها ليست خاصية عامة للمجموعات.

إذا كنت تحاول استخدام مجموعات بهذه الطريقة ، فعليك التفكير في استخدام قائمة بدلاً من ذلك.


java.util.Set هي مجموعة من العناصر غير المحدّدة. لا يوجد أي معنى إذا كان لدى Set (get) (int index) ، لأن Set لا يحتوي على فهرس وأيضا يمكنك تخمين القيمة فقط.

إذا كنت تريد ذلك حقًا ، فقم بتشفير طريقة للحصول على عنصر عشوائي من Set.


لست متأكدا مما إذا كان أي شخص قد حدده بالضبط بهذه الطريقة ، ولكن عليك أن تفهم ما يلي:

لا يوجد عنصر "الأول" في مجموعة.

لأنه ، كما قال الآخرون ، ليس للمجموعات أي طلب. المجموعة عبارة عن مفهوم رياضي لا يتضمن على وجه التحديد طلبًا.

بالطبع ، لا يستطيع الكمبيوتر الخاص بك الاحتفاظ بقائمة الأشياء التي لم يتم طلبها في الذاكرة. يجب أن يكون لديك بعض الطلبات. داخليا هو مجموعة أو قائمة مرتبطة أو شيء من هذا القبيل. لكنك لا تعرف حقاً ما هي ، ولا تحتوي على عنصر أول. العنصر الذي يخرج "الأول" يخرج بهذه الطريقة عن طريق الصدفة ، وقد لا يكون أول مرة في المرة القادمة. حتى لو اتخذت خطوات "لضمان" عنصر أول معين ، فإنه لا يزال يخرج عن طريق الصدفة ، لأنك حصلت للتو على حق لتطبيق واحد معين لمجموعة ؛ قد لا يعمل تنفيذ مختلف بهذه الطريقة مع ما قمت به. وفي الواقع ، قد لا تعرف التطبيق الذي تستخدمه كما تعتقد.

يواجه الناس في هذا ALL. ال. زمن. مع أنظمة RDBMS ولا تفهم. إرجاع استعلام RDBMS مجموعة من السجلات. هذا هو نفس نوع المجموعة من الرياضيات: مجموعة غير مرتبة من العناصر ، فقط في هذه الحالة تكون العناصر عبارة عن سجلات. لا تحتوي نتيجة استعلام RDBMS على أي طلب مضمون على الإطلاق ما لم تستخدم جملة ORDER BY ، ولكن في كل وقت يفترض الناس أنها تفعل ذلك ، ثم يقومون بتدوير أنفسهم في يوم من الأيام عندما يتغير شكل بياناتهم أو رمزهم قليلاً ويؤدي إلى تشغيل مُحسِّن الاستعلام. بطريقة مختلفة وفجأة لا تظهر النتائج بالترتيب الذي يتوقعونه. عادة ما يكون هؤلاء الأشخاص الذين لم يلتفتوا في فئة قاعدة البيانات (أو عند قراءة الوثائق أو البرامج التعليمية) عندما تم شرحها لهم ، مقدمًا ، أن نتائج الاستعلام لا تتضمن طلبًا مضمونًا.


بعض هياكل البيانات مفقودة من مجموعات جافا القياسية.

حقيبة (مثل المجموعة ولكن يمكن أن تحتوي على عناصر عدة مرات)

UniqueList (قائمة مرتبة ، يمكن أن تحتوي على كل عنصر مرة واحدة فقط)

يبدو أنك ستحتاج إلى أخصائي في هذه الحالة

إذا كنت تحتاج إلى هياكل بيانات مرنة ، فقد تكون مهتمًا بمجموعات Google


يرجى ملاحظة أنه يمكن الوصول إلى هيكلين أساسيين فقط للبيانات عبر الفهرس.

  • يمكن الوصول إلى بنية بيانات المصفوفة عبر الفهرس مع تعقيد زمن O(1) لتحقيق عملية get(int index) .
  • يمكن أيضًا الوصول إلى بنية بيانات LinkedList عبر الفهرس ، ولكن مع تعقيد زمن O(n) لتحقيق عملية get(int index) .

في Java ، يتم تنفيذ ArrayList باستخدام بنية بيانات Array .

على الرغم من أنه يمكن عادةً تنفيذ بنية بيانات المجموعة عبر بنية بيانات HashTable / HashMap أو BalancedTree ، وذلك للكشف السريع عما إذا كان العنصر موجودًا وإضافة عنصر غير موجود ، عادةً ما تكون المجموعة التي تم تنفيذها بشكل جيد قادرة على تحقيق O(1) تعقيد زمني contains العملية. في Java ، يعد HashSet أكثر استخدامًا شائعًا لتطبيق Set ، ويتم تنفيذه عن طريق استدعاء HashMap API ، ويتم تطبيق HashMap باستخدام تسلسل منفصل مع القوائم المرتبطة (مجموعة من Array و LinkedList ).

بما أن المجموعة يمكن تنفيذها عبر بنية بيانات مختلفة ، فلا يوجد طريقة get(int index) لها.


يمكنك عمل new ArrayList<T>(set).get(index)


بدلاً من إعادة صياغة جميع الأسباب (العديدة) ضد الاستثناءات المحددة ، سأختار واحدًا فقط. لقد فقدت عدد المرات التي كتبت فيها هذا الكود من الكود:

try {
  // do stuff
} catch (AnnoyingcheckedException e) {
  throw new RuntimeException(e);
}

99 ٪ من الوقت لا أستطيع فعل أي شيء حيال ذلك. أخيرا كتل القيام بأي تنظيف ضروري (أو على الأقل يجب عليهم).

لقد فقدت أيضًا عدد المرات التي رأيتها فيها:

try {
  // do stuff
} catch (AnnoyingCheckedException e) {
  // do nothing
}

لماذا ا؟ لأن شخص ما تعامل معها وكان كسول. هل كان من الخطأ؟ بالتأكيد. هل هذا يحدث؟ إطلاقا. ماذا لو كان هذا استثناء غير محدد؟ سيكون التطبيق قد مات للتو (وهو الأفضل من ابتلاع استثناء).

ثم لدينا رمز غضب يستخدم استثناءات كشكل من أشكال التحكم في التدفق ، مثل java.text.Format . Bzzzt. خطأ. مستخدم وضع "abc" في حقل رقم في نموذج غير استثناء.

حسنا ، أعتقد أن هذا كان ثلاثة أسباب.







java data-structures collections set