জাভা লিস্টকন্টন (এক্স সমান মাঠের মান সহ বস্তু)


199

আমি যাচাই করতে চাই Listযে কোনওটিতে একটি নির্দিষ্ট মান সহ একটি ক্ষেত্র রয়েছে object এখন, আমি যেতে এবং চেক করার জন্য একটি লুপ ব্যবহার করতে পারি, তবে আরও কিছু কোড দক্ষ ছিল কিনা তা জানতে আগ্রহী was

কিছুটা এইরকম;

if(list.contains(new Object().setName("John"))){
    //Do some stuff
}

আমি জানি যে উপরের কোডটি কিছু করে না, কেবলমাত্র আমি যা অর্জন করতে চাইছি তা প্রদর্শন করার জন্য।

এছাড়াও, কেবল স্পষ্ট করার জন্য, আমি একটি সাধারণ লুপটি ব্যবহার করতে চাই না কারণ কারণ এই কোডটি বর্তমানে একটি লুপের ভিতরে যা একটি লুপের অভ্যন্তরে থাকবে inside পাঠযোগ্যতার জন্য আমি এই লুপগুলিতে লুপ যুক্ত রাখতে চাই না don't সুতরাং আমি ভাবলাম যে কোনও সাধারণ (ইশ) বিকল্প আছে কিনা।


5
যেহেতু এটি কাস্টম সমতা, আপনাকে কাস্টম কোড লিখতে হবে।
সোটিরিওস ডেলিমনোলিস

আপনার বর্ণিত লক্ষ্য এবং আপনার কোড উদাহরণটি মিলছে বলে মনে হয় না। আপনি কি কেবলমাত্র একটি ক্ষেত্রের মানের ভিত্তিতে অবজেক্টগুলি তুলনা করতে চান?
ডানকান জোন্স

1
equals(Object)আপনার কাস্টম অবজেক্টের পদ্ধতিটি ওভাররাইড করবেন ?
জোশ এম

1
for(Person p:list) if (p.getName().equals("John") return true; return false;আমি ভীত জাভাতে আপনি আরও সংক্ষিপ্ত পথ খুঁজে পাবেন না।
মাইকফে

@ রাজদীপ দুঃখিত, আমি আপনার প্রশ্নটি বুঝতে পারি না। সর্বদা সত্য p.equals(p) হওয়া উচিত , তাই আপনি যা অর্জন করার চেষ্টা করছেন তা আমি বিভ্রান্ত। আশা করি আপনি যদি নতুন প্রশ্ন জিজ্ঞাসা করেন তবে আরও ভাল সহায়তা পেতে পারেন।
মাইকএফএ

উত্তর:


266

প্রবাহের

আপনি যদি জাভা 8 ব্যবহার করে থাকেন তবে সম্ভবত আপনি এরকম কিছু চেষ্টা করতে পারেন:

public boolean containsName(final List<MyObject> list, final String name){
    return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}

অথবা বিকল্পভাবে, আপনি এই জাতীয় কিছু চেষ্টা করতে পারেন:

public boolean containsName(final List<MyObject> list, final String name){
    return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}

নামের সাথে trueযদি একটি List<MyObject>থাকে তবে এই পদ্ধতিটি ফিরে আসবে । আপনি যদি এর যে কোনও একটিতে একটি অপারেশন করতে চান তবে আপনি এরকম কিছু চেষ্টা করতে পারেন:MyObjectnameMyObjectgetName().equals(name)

public void perform(final List<MyObject> list, final String name){
    list.stream().filter(o -> o.getName().equals(name)).forEach(
            o -> {
                //...
            }
    );
}

যেখানে oএকটি MyObjectউদাহরণ উপস্থাপন করে ।

বিকল্প হিসাবে, মন্তব্যগুলি পরামর্শ হিসাবে (ধন্যবাদ এমকে 10), আপনি এই Stream#anyMatchপদ্ধতিটি ব্যবহার করতে পারেন :

public boolean containsName(final List<MyObject> list, final String name){
    return list.stream().anyMatch(o -> o.getName().equals(name));
}

1
তারপরে, দ্বিতীয় উদাহরণটি হওয়া উচিত public boolean। এছাড়াও, আপনি Objects.equals()যদি ব্যবহার করতে চান তবে হতে o.getName()পারে null
এরিক জাবলো

1
আমি স্রেফ একটি ভৌতিক প্রোগ্রামার। আমি এমন প্রকল্পগুলির সাথে মোকাবিলা করেছি যেখানে লোকেরা নাল দিয়ে দ্রুত এবং আলগা ছিল, তাই আমি প্রতিরক্ষামূলক হতে ঝোঁক। আইটেমগুলি কখনই নালাগুলি না হয় তা নিশ্চিত করার চেয়ে আরও ভাল।
এরিক জাবলো

5
@ এরিকজাব্লো সম্ভবত আপনার কেবলমাত্র একটি উত্তর (আমার) এর বিপরীতে, যাচাই করে না এমন সমস্ত উত্তর সম্পর্কে মন্তব্য করা উচিত null
জোশ এম

55
আরও খাটো এবং বোঝা সহজ: return list.stream().anyMatch(o -> o.getName().equals(name));
এমকে 10

3
আমি @ java.util.Objectsএমকে 10 এর সাথে সম্মত হই return list.stream().anyMatch(o -> Objects.euqals(o.getName(), name);তবে নালসফ তুলনা করার জন্য আমি ব্যবহার করব যদি আপনি নলের জন্য স্ট্রিমে অবজেক্টগুলি পরীক্ষা করতে চান তবে আপনি যে কোনও .filter(Objects::nonNull)ম্যাচের আগে একটি যোগ করতে পারেন ।
tobijdc

81

আপনার দুটি পছন্দ আছে।

১. প্রথম পছন্দটি যা পছন্দনীয় তা হ'ল আপনার অবজেক্ট শ্রেণিতে `সমান ()` পদ্ধতিটি ওভাররাইড করা।

ধরা যাক, উদাহরণস্বরূপ, আপনার এই অবজেক্ট ক্লাসটি রয়েছে:

public class MyObject {
    private String name;
    private String location;
    //getters and setters
}

এখন বলা যাক আপনি কেবল মাইবজেক্টের নাম সম্পর্কেই যত্নশীল, এটি অনন্য হওয়া উচিত তাই যদি দুটি `মাইবজেক্টের একই নাম থাকে তবে তাদের সমান বিবেচনা করা উচিত। সেক্ষেত্রে আপনি `সমান ()` পদ্ধতিটি (এবং এছাড়াও also হ্যাশকোড () `পদ্ধতি) ওভাররাইড করতে চান যাতে এটি সামঞ্জস্যতা নির্ধারণের জন্য নামের সাথে তুলনা করে।

একবার আপনি এটি সম্পন্ন করার পরে, আপনি কোনও সংগ্রহের মতো "foo" নামের একটি মাইবজেক্ট রয়েছে কিনা তা পরীক্ষা করে দেখতে পারেন:

MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);

তবে এটি আপনার পক্ষে বিকল্প নাও হতে পারে যদি:

  • সাম্যতা যাচাই করার জন্য আপনি নাম এবং অবস্থান উভয়ই ব্যবহার করছেন তবে আপনি কেবল এটি অনুসন্ধান করতে চান যে কোনও সংগ্রহে নির্দিষ্ট অবস্থানের সাথে কোনও `মাইবজেক্ট` রয়েছে কিনা। এই ক্ষেত্রে, আপনি ইতিমধ্যে `সমান ()` কে ওভাররাইড করেছেন `
  • `মাইওবজেক্ট` এমন একটি এপিআই-র অংশ যা আপনার পরিবর্তনের স্বাধীনতা নেই।

যদি এগুলির কোনও একটি হয় তবে আপনি বিকল্প 2:

২. আপনার নিজস্ব ইউটিলিটি পদ্ধতি লিখুন:

public static boolean containsLocation(Collection<MyObject> c, String location) {
    for(MyObject o : c) {
        if(o != null && o.getLocation.equals(location)) {
            return true;
        }
    }
    return false;
}

বিকল্পভাবে, আপনি অ্যারেলিস্ট (বা অন্য কোনও সংগ্রহ) প্রসারিত করতে পারেন এবং তারপরে এটিতে নিজের নিজস্ব পদ্ধতি যুক্ত করতে পারেন:

public boolean containsLocation(String location) {
    for(MyObject o : this) {
        if(o != null && o.getLocation.equals(location)) {
                return true;
            }
        }
        return false;
    }

দুর্ভাগ্যক্রমে এর কাছাকাছি আর ভাল উপায় নেই।


আমি মনে করি আপনি গেটের জন্য বন্ধনীগুলি ভুলে গেছেন যদি (ও! = নাল && o.getLocation.equals (অবস্থান))
ওলজি

25

গুগল পেয়ারা

আপনি যদি পেয়ারা ব্যবহার করছেন তবে আপনি কার্যকরী পদ্ধতি গ্রহণ করতে পারেন এবং নিম্নলিখিতগুলি করতে পারেন

FluentIterable.from(list).find(new Predicate<MyObject>() {
   public boolean apply(MyObject input) {
      return "John".equals(input.getName());
   }
}).Any();

যা দেখতে কিছুটা ভার্জোজ। তবে প্রিডিকেট হ'ল একটি অবজেক্ট এবং আপনি বিভিন্ন অনুসন্ধানের জন্য বিভিন্ন রূপ সরবরাহ করতে পারেন। গ্রন্থাগারটি কীভাবে সংগ্রহের পুনরাবৃত্তি এবং আপনি যে ফাংশন প্রয়োগ করতে চান তা কীভাবে পৃথক করে তা নোট করুন। equals()কোনও নির্দিষ্ট আচরণের জন্য আপনাকে ওভাররাইড করতে হবে না ।

নীচে উল্লিখিত হিসাবে, java.util.Stream ফ্রেমওয়ার্কটি জাভা 8 এর মধ্যে নির্মিত এবং পরে অনুরূপ কিছু সরবরাহ করে।


1
বিকল্পভাবে আপনি ব্যবহার করতে পারেন Iterables.any(list, predicate), যা ব্যবহারিকভাবে একই, এবং আপনি এটি স্টাইলিস্টিকভাবে পছন্দ করতে পারেন বা নাও করতে পারেন।
মাইকফে

নিবন্ধন করুন :) আপনি আমার সমাধান তাকান পারে।
জোশ এম

25

জাভা 8+ ব্যবহার করে এটি কীভাবে করা যায়:

boolean isJohnAlive = list.stream().anyMatch(o -> o.getName().equals("John"));

20

Collection.contains()equals()এক অবধি প্রত্যাবর্তন প্রতিটি অবজেক্টে কল করে প্রয়োগ করা হয় true

সুতরাং এটি প্রয়োগ করার একটি উপায় হ'ল ওভাররাইড করা equals()তবে অবশ্যই আপনার কেবলমাত্র একটি সমতুল্য থাকতে পারে।

পেয়ারা জাতীয় কাঠামো তাই এর জন্য পূর্বাভাস ব্যবহার করে। এর সাথে Iterables.find(list, predicate), আপনি পরীক্ষাকে প্রিকিটের মধ্যে রেখে স্বেচ্ছাসেবী ক্ষেত্রগুলি অনুসন্ধান করতে পারেন।

ভিএম এর উপরে নির্মিত অন্যান্য ভাষাগুলিতে এটি অন্তর্নির্মিত রয়েছে Gro গ্রোভিতে , উদাহরণস্বরূপ, আপনি কেবল লিখুন:

def result = list.find{ it.name == 'John' }

জাভা 8 আমাদের সমস্ত জীবনকে আরও সহজ করে তুলেছে:

List<Foo> result = list.stream()
    .filter(it -> "John".equals(it.getName())
    .collect(Collectors.toList());

আপনি যদি এই জাতীয় বিষয়ে যত্নশীল হন তবে আমি "জাভা ছাড়িয়ে" বইয়ের পরামর্শ দিই। এটি জাভার অসংখ্য ত্রুটিগুলির জন্য এবং অন্যান্য ভাষাগুলি কীভাবে আরও ভাল করে তার জন্য অনেকগুলি উদাহরণ রয়েছে।


সুতরাং, যদি আমি কাস্টম অবজেক্টগুলির তালিকার সাথে যুক্ত হওয়ার সমান পদ্ধতিটি ওভাররাইড করি ... নির্দিষ্ট শ্রেণীর ভেরিয়েবলগুলি একই হয় তবে আমি কি এটি ঠিক সত্যটিতে ফিরে পেতে পারি?
রুডি কারশওয়া

1
না, পিছনে ধারণাটি equals()খুব সীমাবদ্ধ। এর অর্থ "অবজেক্ট আইডেন্টিটি" যাচাই করা - যা কিছু শ্রেণীর অবজেক্টের জন্য এর অর্থ হতে পারে। যদি আপনি একটি পতাকা যুক্ত করেন তবে কোন ক্ষেত্রগুলি অন্তর্ভুক্ত করা উচিত, এটি সমস্ত ধরণের সমস্যার কারণ হতে পারে। আমি এর বিরুদ্ধে দৃ .়ভাবে পরামর্শ দিচ্ছি।
অ্যারন দিগুল্লা 17'13

গ্রোভিকে ভালবাসুন, তাই "নতুন" জাভা 8 লাম্বদা সত্যিই এখনও আমাদের এই শীতলতা দেয় না? def result = list.find{ it.name == 'John' }প্রোগ্রামারদের বিরুদ্ধে যুদ্ধাপরাধের জন্য ওরাকল / জেসিপি মামলা করা উচিত।
কেন

19

বাইনারি অনুসন্ধান

আপনি আপনার তালিকার একটি উপাদান অনুসন্ধান করতে কালেকশনস.বাইনারি অনুসন্ধান ব্যবহার করতে পারেন (ধরে নিচ্ছেন তালিকাকে সাজানো হয়েছে):

Collections.binarySearch(list, new YourObject("a1", "b",
                "c"), new Comparator<YourObject>() {

            @Override
            public int compare(YourObject o1, YourObject o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });

বস্তুটি সংগ্রহে উপস্থিত না থাকলে এটি একটি নেতিবাচক সংখ্যাটি ফিরিয়ে দেবে অথবা অন্যথায় এটি indexবস্তুর প্রত্যাবর্তন করবে । এটির সাহায্যে আপনি বিভিন্ন অনুসন্ধান কৌশল সহ অবজেক্টগুলি অনুসন্ধান করতে পারেন।


এটি এমন ছোট প্রকল্পগুলির জন্য দুর্দান্ত সমাধান যা পেয়ারা ব্যবহার করতে চান না। যদিও একটি প্রশ্ন, বাইনারি অনুসন্ধানের ডক্সে বলা হয়েছে: "এই কল করার আগে তালিকাটি অবশ্যই নির্দিষ্ট তুলনা অনুযায়ী অনুসারে বাছাই করা উচিত it তবে কিছু ক্ষেত্রে মনে হচ্ছে, কি তুলনা করা হচ্ছে তার উপর নির্ভর করে এই ঘটনাটি নাও হতে পারে?
ক্রিসমার্কস

এবং youণাত্মক সংখ্যাটি উপস্থাপন করে যেখানে বস্তুটি সন্নিবেশ করা হবে এবং যদি আপনি এটি পুনরায় সাজান তবে।
fiorentinoing

8

মানচিত্র

আপনি একটি Hashmap<String, Object>মানকে কী হিসাবে ব্যবহার করে তৈরি করতে পারেন এবং তারপরে yourHashMap.keySet().contains(yourValue)সত্যটি ফিরে আসে কি না।


+1 যদিও এর অর্থ ম্যাপে বিশদটি প্রথম স্থানে রাখার পরে কিছুটা ওভারহেডের পরে আপনি ধ্রুবক সময় অনুসন্ধান পান। আমি অবাক হয়েছি এখন পর্যন্ত কেউ এ বিষয়ে পরামর্শ দেয়নি।
রুডি Kershaw

6

গ্রহগ্রহের সংগ্রহ

আপনি যদি গ্রিপস সংগ্রহগুলি ব্যবহার করছেন তবে আপনি anySatisfy()পদ্ধতিটি ব্যবহার করতে পারেন । হয় আপনার খাপ খাওয়ানো Listএকটি ListAdapterঅথবা আপনার পরিবর্তন Listএকটি মধ্যে ListIterableযদি সম্ভব।

ListIterable<MyObject> list = ...;

boolean result =
    list.anySatisfy(myObject -> myObject.getName().equals("John"));

আপনি যদি এই ঘন ঘন অপারেশন করেন, তবে এমন কোনও পদ্ধতি বের করা ভাল যা এই ধরণের বৈশিষ্ট্যযুক্ত কিনা তা উত্তর দেয় whether

public class MyObject
{
    private final String name;

    public MyObject(String name)
    {
        this.name = name;
    }

    public boolean named(String name)
    {
        return Objects.equals(this.name, name);
    }
}

আপনি anySatisfyWith()একটি পদ্ধতি রেফারেন্স সহ একসাথে বিকল্প ফর্মটি ব্যবহার করতে পারেন ।

boolean result = list.anySatisfyWith(MyObject::named, "John");

আপনি যদি এটিকে Listকোনও রূপান্তর করতে না পারেন তবে আপনি ListIterableকীভাবে ব্যবহার করবেন তা এখানে ListAdapter

boolean result = 
    ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");

দ্রষ্টব্য: আমি গ্রহগ্রহের সংগ্রহের প্রতিশ্রুতিবদ্ধ।


5

Predicate

আপনি যদি জাভা 8 ব্যবহার করেন না বা গ্রন্থাগার যা আপনাকে সংগ্রহগুলি মোকাবেলা করার জন্য আরও কার্যকারিতা দেয়, আপনি এমন কোনও কিছু প্রয়োগ করতে পারেন যা আপনার সমাধানের চেয়ে পুনরায় ব্যবহারযোগ্য হতে পারে।

interface Predicate<T>{
        boolean contains(T item);
    }

    static class CollectionUtil{

        public static <T> T find(final Collection<T> collection,final  Predicate<T> predicate){
            for (T item : collection){
                if (predicate.contains(item)){
                    return item;
                }
            }
            return null;
        }
    // and many more methods to deal with collection    
    }

আমি এরকম কিছু ব্যবহার করছি, আমার কাছে প্রিফিকেট ইন্টারফেস রয়েছে এবং আমি এটি ব্যবহারের ক্লাসে প্রয়োগ করে চলেছি।

আমার পথে এটি করার সুবিধা কী? আপনার কাছে এমন একটি পদ্ধতি রয়েছে যা কোনও প্রকারের সংগ্রহে অনুসন্ধান করে। এবং আপনি যদি আলাদা ক্ষেত্রের দ্বারা অনুসন্ধান করতে চান তবে আপনাকে আলাদা পদ্ধতি তৈরি করতে হবে না। আপনাকে যা করতে হবে তা হ'ল আলাদা প্রিকিকেট সরবরাহ করা যা এটি আর ব্যবহারযোগ্য / না হয়ে যাওয়ার সাথে সাথে ধ্বংস হতে পারে /

আপনি যদি এটি ব্যবহার করতে চান তবে আপনাকে যা করতে হবে তা হ'ল কল পদ্ধতি এবং আপনার প্রাকটিকাকে সংজ্ঞায়িত করতে হবে

CollectionUtil.find(list, new Predicate<MyObject>{
    public boolean contains(T item){
        return "John".equals(item.getName());
     }
});

4

পেয়ারা ব্যবহার করে একটি সমাধান এখানে দেওয়া হল

private boolean checkUserListContainName(List<User> userList, final String targetName){

    return FluentIterable.from(userList).anyMatch(new Predicate<User>() {
        @Override
        public boolean apply(@Nullable User input) {
            return input.getName().equals(targetName);
        }
    });
}

3

containsপদ্ধতি equalsঅভ্যন্তরীণভাবে ব্যবহার করে। সুতরাং আপনার প্রয়োজন অনুসারে equalsআপনার ক্লাসের পদ্ধতিটি ওভাররাইড করা দরকার।

বিটিডব্লিউটি সিনট্যাটিকভাবে সঠিক দেখাচ্ছে না:

new Object().setName("John")

3
যদি না সেটার ফিরে না আসে this
সোটিরিওস ডেলিমনোলিস

সুতরাং, যদি আমি কাস্টম অবজেক্টগুলির তালিকার সাথে যুক্ত হওয়ার সমান পদ্ধতিটি ওভাররাইড করি ... নির্দিষ্ট শ্রেণীর ভেরিয়েবলগুলি একই হয় তবে আমি কি এটি ঠিক সত্যটিতে ফিরে পেতে পারি?
রুডি কারশওয়া

@ রূডিকারশাহ হ্যাঁ এটিই ধারণা, আপনি এক / দুই / সমস্ত ক্ষেত্রের ভিত্তিতে সত্য ফিরে আসতে পারেন। সুতরাং আপনি যদি বিশ্বাস করেন যে যুক্তিযুক্তভাবে একই নামযুক্ত দুটি বস্তু সমান বস্তু হিসাবে বলা হয় তবে কেবল নামগুলি একত্রিত করে সত্যে ফিরে আসুন।
জুনেদ আহসান

1
এটি equalsএকক ব্যবহারের ক্ষেত্রে ওভাররাইড করার পক্ষে যুক্তিযুক্ত নয় , যদি না এটি সাধারণভাবে শ্রেণীর জন্য বোঝায়। আপনি কেবল লুপটি লেখার চেয়ে আরও ভাল হবেন।
মাইকফে

@ মাইকএফএই রাজি হয়েছে, কেন আমি মন্তব্যে উল্লেখ করেছি "তাই যদি আপনি বিশ্বাস করেন যে যুক্তিযুক্তভাবে সঠিক নামের সাথে একই নামের দুটি বস্তু সমান বস্তু হয় তবে সত্য ফিরে
আসুন

1

আপনার যদি List.contains(Object with field value equal to x)বারবার এটি সম্পাদন করার প্রয়োজন হয় তবে একটি সহজ এবং দক্ষ কাজ হবে:

List<field obj type> fieldOfInterestValues = new ArrayList<field obj type>;
for(Object obj : List) {
    fieldOfInterestValues.add(obj.getFieldOfInterest());
}

তাহলে এর List.contains(Object with field value equal to x)একই ফলাফল হবে resultfieldOfInterestValues.contains(x);


1

আপনি এটি anyMatch()ব্যবহার করতে পারেন:

public boolean containsName(final List<MyObject> list, final String name){
    return list.stream().anyMatch(o -> o.getName().contains(name));
}

0

জাভা 8 SDK এর সত্ত্বেও সংগ্রহ সরঞ্জামের একটি অনেক লাইব্রেরি সঙ্গে কাজ করার আপনাকে সহায়তা করতে পারে, উদাহরণস্বরূপ থাকে: http://commons.apache.org/proper/commons-collections/

Predicate condition = new Predicate() {
   boolean evaluate(Object obj) {
        return ((Sample)obj).myField.equals("myVal");
   }
};
List result = CollectionUtils.select( list, condition );
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.