列表:过滤类似元素的惯用法

时间:2018-03-13 08:31:10

标签: list kotlin

我正在寻找distinct的反面。

在包含[ "a", "a", "b", "c", "b", "d" ]的列表中,我只想保留"a""b",因为它们会多次出现。

解决方法可能如下:

val similarsList = mutableListOf<String>()
list.filter { 
    if (similars.contains(it))
        return@filter true
    similars.add(it)
    false
}.distinct()

这将删除与之前已包含的元素匹配的每个元素。在list对象中,所有出现多次的元素都将存储在filter之后。在这种情况下,distinct会清除出现过三次或更多次的元素。

正在寻找一种惯用的方式正是这样做的,与distinct相反。

3 个答案:

答案 0 :(得分:13)

使用Kotlin 1.1标准库中引入的API,@gil.fernandes可以对.groupingBy { ... }提供的解决方案进行小改进:Grouping。它不是立即创建组,而是创建一个惰性.eachCount(),然后可以查询它。特别是,我们可以要求{{3}},它返回Map<T, Int>

val l = listOf("a", "a", "b", "c", "b", "d")

val result = l.groupingBy { it }.eachCount().filterValues { it > 1 }.keys

它比使用.groupBy { ... }更有效,因为它不会将列存储在列表中。

答案 1 :(得分:7)

如果您想过滤掉重复项(非不同项目),可以尝试:

import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;

import java.util.HashMap;
import java.util.Map;


public class PersonalDetailsFragment extends Fragment {

    // Code variables
    boolean male = true;
    boolean radioButtonSelected = false;

    String firstName;
    String initials;
    String lastName;
    String current_uid;

    // Layout Fields
    private TextInputLayout mFirstName;
    private TextInputLayout mInitials;
    private TextInputLayout mLastName;
    private Button mContinueBtn;
    private RadioButton mFemale;
    private RadioButton mMale;

    //Firebase Auth
    private FirebaseAuth mAuth;
    private DatabaseReference mUserDatabase;
    private FirebaseUser mCurrentUser;

    //ProgressDialog
    private ProgressDialog mProgressDialog;

    // View Pager
    private ViewPager mViewPager;

    // View
    View view;

    public PersonalDetailsFragment() {
        // Required empty public constructor
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        // Inflate the layout for this fragment
        view = inflater.inflate(R.layout.fragment_personal_details, container, false);

        // Button(s) Initialisation
        mContinueBtn = (Button) view.findViewById(R.id.btnContinue);

        // Firebase Initialisation
        mAuth = FirebaseAuth.getInstance();

        mCurrentUser = FirebaseAuth.getInstance().getCurrentUser();
        current_uid = mCurrentUser.getUid();

        mUserDatabase = FirebaseDatabase.getInstance().getReference().child("Users").child(current_uid);
        mUserDatabase.keepSynced(true);

        // Progress Bar Initialisation
        mProgressDialog = new ProgressDialog(getActivity());

        // View Pager Initialisation
        mViewPager = (ViewPager) getActivity().findViewById(R.id.main_tabPager);

        // Layout fields Initialisation
        mFirstName = (TextInputLayout) view.findViewById(R.id.inputFirstName);
        mInitials = (TextInputLayout) view.findViewById(R.id.inputInitials);
        mLastName = (TextInputLayout) view.findViewById(R.id.inputLastName);


        mUserDatabase.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {

                if (FirebaseDatabase.getInstance().getReference().child("Users").child("first_name") == null)
                {

                    String ofirst_name = dataSnapshot.child("first_name").getValue().toString();


                    mFirstName.getEditText().setText(ofirst_name);

                }// end of if

                if (FirebaseDatabase.getInstance().getReference().child("Users").child("initials") == null)
                {

                    String oinitials = dataSnapshot.child("initials").getValue().toString();

                    mInitials.getEditText().setText(oinitials);

                }// end of if

                if (FirebaseDatabase.getInstance().getReference().child("Users").child("last_name") == null)
                {

                    String olast_name = dataSnapshot.child("last_name").getValue().toString();

                    mLastName.getEditText().setText(olast_name);

                }// end of if

            } // end of onDataChange ()

            @Override
            public void onCancelled(DatabaseError databaseError) {

            }

        });

        mContinueBtn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {

                firstName = mFirstName.getEditText().getText().toString();
                initials = mInitials.getEditText().getText().toString();
                lastName = mLastName.getEditText().getText().toString();


                if ( TextUtils.isEmpty( firstName ) || TextUtils.isEmpty( initials ) || TextUtils.isEmpty( lastName ) || radioButtonSelected == false )
                {
                    Toast.makeText( getActivity().getApplicationContext(), "Make sure all fields are filled in.", Toast.LENGTH_LONG ).show();
                } else {

                    mProgressDialog.setTitle("Saving Details");
                    mProgressDialog.setMessage("Please wait while we save your details...");
                    mProgressDialog.setCanceledOnTouchOutside(false);
                    mProgressDialog.show();

                    update_user();

                } // end of if

            } // end of onClick

        }); // end of mContinueBtn.setOnClickListener

        // Declaring and Initialising radio buttons
        final RadioGroup radioGroup = (RadioGroup) view.findViewById(R.id.gender);

        radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(RadioGroup group, int checkedId) {
                switch (checkedId) {
                    case R.id.radioMale:
                        male = true;
                        radioButtonSelected = true;
                        break;
                    case R.id.radioFemale:
                        male = false;
                        radioButtonSelected = true;
                        break;

                } // end of switch statement

            } // end of onCheckedChanged

        }); // end of radioGroup.setOnCheckedChangeListener

        return view;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {

        // save views as variables in this method
        // "view" is the one returned from onCreateView
        // Android Fields

    }

        private void update_user() {

            Map update_hashMap = new HashMap();
            update_hashMap.put("first_name", firstName);
            update_hashMap.put("last_name", lastName);
            update_hashMap.put("initials", initials);


            mUserDatabase.setValue(update_hashMap).addOnCompleteListener(new OnCompleteListener<Void>() {
                @Override
                public void onComplete(@NonNull Task<Void> task) {

                    if(task.isSuccessful()){

                        mProgressDialog.dismiss();
                        mViewPager.setCurrentItem(1);
                        Toast.makeText(getActivity().getApplicationContext(), "Success Uploading.", Toast.LENGTH_LONG).show();

                    }

                }
            });


    } // end of update_user

}    

打印出来:

fun main(args: Array<String>) {
    val l = listOf( "a", "a", "b", "c", "b", "d" )
    println(l.groupBy { it }.filter { it.value.size > 1 }.keys)
}

说明:[a, b] 生成包含此内容的分组地图:

l.groupBy { it }

然后将过滤器应用于此地图,按值(列表)过滤,其长度优先于1:{a=[a, a], b=[b, b], c=[c], d=[d]}

最后,使用filter { it.value.size > 1 }提取密钥。

答案 2 :(得分:0)

我看到这个问题已经得到了回答,但以防万一有人正在寻找比使用组更有效的方法。

哪里可以这样做

import numpy as np

def encode_state(state):
    a=0
    for i,num in enumerate(state.reshape(9)) :
        a = a + 3**i * int(num)
    return a.to_bytes(2,'big')

def decode_state(byte): 
    encoded_value = int.from_bytes(byte,'big')
    b = [0 for i in range(9)]
    for i in range(9) :
        num = (encoded_value // 3**i) % 3
        b[i] = num
    return np.array(b).reshape(3,3) 
input_state = np.array((
    (2, 2, 2),
    (1, 2, 2),
    (2, 1, 0)),
    dtype="int32")

state_as_byte = encode_state(input_state)
output_state = decode_state(state_as_byte)

print (''.join('{:02x}'.format(x) for x in state_as_byte))
print(output_state)

虽然这完全有效,但如果您需要效率,最好只使用 for 循环和 HashSets

从我的测试中我发现这更有效、更快

val list = listOf(0,1,2,3,4,5,0)

//Gives you group of duplicated numbers. In this case just 0
val group = list.groupBy{it}.filter{it.values.size>1}.keys