问:
How to store arrays in strings.xml or assets and use in ListViewAdapter
I want to create more than 1500 LyricsFullDetail in the ListViewAdapter, but my problem is i don't want to hardcode the Lyrics Full Detail in the the ListViewAdapter.java. I want to store the lyrics full detail and read from Strings.xml or assets folder. The music files are saved in the raw folder.
I will so much appreciate if you help me with an example fix.thanks Below are my codes.

This is the itemClick codes i repeated into 1500 times which gave me 'code too large error'

That is why I'm struggling to save it somewhere like assets folder and read in ListViewAdapter

 //listview item clicks
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //code later
                if (modellist.get(i).getTitle().equals("Song 001 | This song lyrics 1")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("actionBarTitle", "Song 001");
                    intent.putExtra("position", 1);
                    intent.putExtra("contentTv", "1. O THOU to whose all-searching sight\n" +
                            "The darkness shineth as the light,\n" +
                            "Search, prove my heart, it pants for thee;\n" +
                            "O burst these bonds and set it free!\n" +
                            "\n" +
                            "2. Wash out its stain, refine its dross,\n" +
                            "Nail my affections to the cross:\n" +
                            "Hallow each thought, let all within\n" +
                            "Be clean, as thou, my Lord, art clean.");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 002 | This song lyrics 2")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 2);
                    intent.putExtra("actionBarTitle", "Song 002");
                    intent.putExtra("contentTv", "3 Saviour, where’er thy steps I see,\n" +
                            "Dauntless, untired, I’ll follow thee;\n" +
                            "O let thy hand support me still\n" +
                            "And lead me to thy holy hill!\n" +
                            "\n" +
                            "4 If rough and thorny be the way,\n" +
                            "My strength proportion to my day,\n" +
                            "Till toil and grief and pain shall cease,\n" +
                            "Where all is calm and joy and peace.");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 003 | This song lyrics 3")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 3);
                    intent.putExtra("actionBarTitle", "Song 003");
                    intent.putExtra("contentTv", "1. O THOU to whose all-searching sight\n" +
                            "The darkness shineth as the light,\n" +
                            "Search, prove my heart, it pants for thee;\n" +
                            "O burst these bonds and set it free!\n" +
                            "\n" +
                            "2. Wash out its stain, refine its dross,\n" +
                            "Nail my affections to the cross:\n" +
                            "Hallow each thought, let all within\n" +
                            "Be clean, as thou, my Lord, art clean.");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 004 | This song lyrics 4")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 4);
                    intent.putExtra("actionBarTitle", "Song 004");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 005 | This song lyrics 5")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 5);
                    intent.putExtra("actionBarTitle", "Song 005");
                    intent.putExtra("contentTv", "This is song lyrics detail");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 006 | This song lyrics 6")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 6);
                    intent.putExtra("actionBarTitle", "Song 006");
                    intent.putExtra("contentTv", "This is song lyrics detail");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 007 | This song lyrics 7")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 7);
                    intent.putExtra("actionBarTitle", "Song 007");
                    intent.putExtra("contentTv", "This is song lyrics detail");
                    mContext.startActivity(intent);
                }

            }
        });

        return view;
    }```
</div>
</div>
</p>

<p><strong>This is the ListViewAdapter.java</strong></p>

<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code>public class ListViewAdapter extends BaseAdapter {

    //Variables
    Context mContext;
    LayoutInflater inflater;
    List<Model> modellist;
    ArrayList<Model> arrayList;
    int[] soundfile;

    //Constructor
    public ListViewAdapter(Context context, List<Model> modellist) {
        mContext = context;
        this.modellist = modellist;
        inflater = LayoutInflater.from(mContext);
        this.arrayList = new ArrayList<Model>();
        this.arrayList.addAll(modellist);
    }

    public class ViewHolder {
        TextView mTitleTv, mDescTv;
        ImageView mIconTv, favorite;
    }

    @Override
    public int getCount() {
        return modellist.size();
    }

    @Override
    public Object getItem(int i) {
        return modellist.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(final int i, View view, ViewGroup parent) {
        final ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();
            view = inflater.inflate(R.layout.row, null);

            //locate the views in row.xml
            holder.mTitleTv = (TextView) view.findViewById(R.id.mainTitle);
            holder.mDescTv = (TextView) view.findViewById(R.id.mainDesc);
            holder.mIconTv = view.findViewById(R.id.mainIcon);
            //initialize the favorite image view
            holder.favorite = view.findViewById(R.id.favorite);

            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }
        //set the result into textview
        holder.mTitleTv.setText(modellist.get(i).getTitle());
        holder.mDescTv.setText(modellist.get(i).getDesc());
        //Set the result in imagview
        holder.mIconTv.setImageResource(modellist.get(i).getIcon());

        if (modellist.get(i).isFavorite())
            holder.favorite.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_heart));
        else
            holder.favorite.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_heart_o));

        //listview soundfile file for songs in position
        soundfile = new int[]{R.raw.song_1, R.raw.song_2, R.raw.song_3, R.raw.song_4, R.raw.song_5, R.raw.song_6, R.raw.song_7, R.raw.song_8,};

        //fovarite/unfavorite

        holder.favorite.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (modellist.get(i).isFavorite())
                    holder.favorite.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_heart_o));
                else
                    holder.favorite.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_heart));

                modellist.get(i).setFavorite();
            }
        });

        //listview item clicks
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //code later
                if (modellist.get(i).getTitle().equals("Song 001 | This song lyrics 1")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("actionBarTitle", "Song 001");
                    intent.putExtra("position", 1);
                    intent.putExtra("contentTv", "1. O THOU to whose all-searching sight\n" +
                            "The darkness shineth as the light,\n" +
                            "Search, prove my heart, it pants for thee;\n" +
                            "O burst these bonds and set it free!\n" +
                            "\n" +
                            "2. Wash out its stain, refine its dross,\n" +
                            "Nail my affections to the cross:\n" +
                            "Hallow each thought, let all within\n" +
                            "Be clean, as thou, my Lord, art clean.\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 002 | This song lyrics 2")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 2);
                    intent.putExtra("actionBarTitle", "Song 002");
                    intent.putExtra("contentTv", "3 Saviour, where’er thy steps I see,\n" +
                            "Dauntless, untired, I’ll follow thee;\n" +
                            "O let thy hand support me still\n" +
                            "And lead me to thy holy hill!\n" +
                            "\n" +
                            "4 If rough and thorny be the way,\n" +
                            "My strength proportion to my day,\n" +
                            "Till toil and grief and pain shall cease,\n" +
                            "Where all is calm and joy and peace.\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 003 | This song lyrics 3")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 3);
                    intent.putExtra("actionBarTitle", "Song 003");
                    intent.putExtra("contentTv", "1. O THOU to whose all-searching sight\n" +
                            "The darkness shineth as the light,\n" +
                            "Search, prove my heart, it pants for thee;\n" +
                            "O burst these bonds and set it free!\n" +
                            "\n" +
                            "2. Wash out its stain, refine its dross,\n" +
                            "Nail my affections to the cross:\n" +
                            "Hallow each thought, let all within\n" +
                            "Be clean, as thou, my Lord, art clean.\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 004 | This song lyrics 4")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 4);
                    intent.putExtra("actionBarTitle", "Song 004");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 005 | This song lyrics 5")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 5);
                    intent.putExtra("actionBarTitle", "Song 005");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 006 | This song lyrics 6")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 6);
                    intent.putExtra("actionBarTitle", "Song 006");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 007 | This song lyrics 7")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 7);
                    intent.putExtra("actionBarTitle", "Song 007");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }

            }
        });

        return view;
    }

    //filter
    public void filter(String charText) {
        charText = charText.toLowerCase(Locale.getDefault());
        modellist.clear();
        if (charText.length() == 0) {
            modellist.addAll(arrayList);
        } else {
            for (Model model : arrayList) {
                if (model.getTitle().toLowerCase(Locale.getDefault()).contains(charText)) {
                    modellist.add(model);
                }
            }
        }
        notifyDataSetChanged();
    }

}</code>```

This is the MainActivity.java where i saved the list arrays

public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
    private String TAG = "MainActivity ----- ; " ;
    // Store instance variables

    private int page;
    private ConsentForm form;

    ListView listView;
    ListViewAdapter adapter;
    String[] title;
    String[] description;
    int[] icon;
    ArrayList<Model> arrayList = new ArrayList<Model>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //initialize preferences
        PreferenceUtils.initialize(getApplicationContext());

        ActionBar actionBar = getSupportActionBar();
        actionBar.setTitle("Redeemed Songs");

        title = new String[]{"Song 001 | This song lyrics 1","Song 002 | This song lyrics 2","Song 003 | This song lyrics 3","Song 004 | This song lyrics 4","Song 005 | This song lyrics 5","Song 006 | This song lyrics 6","Song 007 | This song lyrics 7"};

        description = new String[]{"MORNING song", "MORNING song", "MORNING song", "MORNING song", "MORNING song", "MORNING song", "MORNING song",};

        icon = new int[]{ R.drawable.song, R.drawable.song, R.drawable.song, R.drawable.song,R.drawable.song,R.drawable.song, R.drawable.song,};

        listView = findViewById(R.id.list);

        for (int i =0; i<title.length; i++){
            Model model =new Model(title[i], description[i], icon[i]);
            //let's simply say, the song identifier is just the order of the song in the list
            model.id = i;
            //bind all strings in an array
            arrayList.add(model);
        }

        //pass result to listview class
        adapter = new ListViewAdapter(this, arrayList);

        //bind the adapter to the listview class
        listView.setAdapter(adapter);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);

        MenuItem myActionMenuItem = menu.findItem(R.id.action_search);
        SearchView searchView = (SearchView)myActionMenuItem.getActionView();
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String s) {
                if (TextUtils.isEmpty(s)){
                    adapter.filter("");
                    listView.clearTextFilter();
                }
                else {
                    adapter.filter(s);
                }
                return true;
            }
        });

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id==R.id.action_settings){
            Toast.makeText(this, "Settings Selected", Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, Main2Activity.class));
            return true;
            //do your funtionality here

        }
        else if (id==R.id.action_howtouse){
                Toast.makeText(this, "How-To", Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, FavoriteListActivity.class));
            return true;
                //do your funtionality here

        }else if (id==R.id.action_favorites){
                Toast.makeText(this, "Favorites Selected", Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, FavoriteListActivity.class));
            return true;
                //do your funtionality here

        }
        else if (id==R.id.action_developers){
            Toast.makeText(this, "About", Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, Main4Activity.class));
            return true;
            //do your funtionality here

        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        return false;
    }
}```

答:
You can create a List from and String Array in the strings.xml this can then be then be used in and Adapter, you could have a parallel array to match the Song title to Lyrics

But you are probably better using an SQLite database for this type of stuff either directly or Using Android Rooms.

Training material for rooms (which is a layer on top of SQLite) https://developer.android.com/training/data-storage/room/

or more direct https://developer.android.com/training/data-storage/sqlite.html

List<String> myLyricList = Arrays.asList(getResources().getStringArray(R.array.array_lyrics));

List<String> myTitleList = Arrays.asList(getResources().getStringArray(R.array.array_titles));

```

<p>strings.xml</p>

<pre class="lang-xml prettyprint-override"><code><string-array name="array_lyrics">
        <item>This song lyrics 1</item>
        <item>This song lyrics 2</item>
</string-array>

<string-array name="array_titles">
        <item>Song 001</item>
        <item>Song 002</item>
</string-array>

</code>```

Body:
I want to create more than 1500 LyricsFullDetail in the ListViewAdapter, but my problem is i don't want to hardcode the Lyrics Full Detail in the the ListViewAdapter.java. I want to store the lyrics full detail and read from Strings.xml or assets folder. The music files are saved in the raw folder.
I will so much appreciate if you help me with an example fix.thanks Below are my codes.

This is the itemClick codes i repeated into 1500 times which gave me 'code too large error'

That is why I'm struggling to save it somewhere like assets folder and read in ListViewAdapter

 //listview item clicks
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //code later
                if (modellist.get(i).getTitle().equals("Song 001 | This song lyrics 1")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("actionBarTitle", "Song 001");
                    intent.putExtra("position", 1);
                    intent.putExtra("contentTv", "1. O THOU to whose all-searching sight\n" +
                            "The darkness shineth as the light,\n" +
                            "Search, prove my heart, it pants for thee;\n" +
                            "O burst these bonds and set it free!\n" +
                            "\n" +
                            "2. Wash out its stain, refine its dross,\n" +
                            "Nail my affections to the cross:\n" +
                            "Hallow each thought, let all within\n" +
                            "Be clean, as thou, my Lord, art clean.");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 002 | This song lyrics 2")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 2);
                    intent.putExtra("actionBarTitle", "Song 002");
                    intent.putExtra("contentTv", "3 Saviour, where’er thy steps I see,\n" +
                            "Dauntless, untired, I’ll follow thee;\n" +
                            "O let thy hand support me still\n" +
                            "And lead me to thy holy hill!\n" +
                            "\n" +
                            "4 If rough and thorny be the way,\n" +
                            "My strength proportion to my day,\n" +
                            "Till toil and grief and pain shall cease,\n" +
                            "Where all is calm and joy and peace.");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 003 | This song lyrics 3")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 3);
                    intent.putExtra("actionBarTitle", "Song 003");
                    intent.putExtra("contentTv", "1. O THOU to whose all-searching sight\n" +
                            "The darkness shineth as the light,\n" +
                            "Search, prove my heart, it pants for thee;\n" +
                            "O burst these bonds and set it free!\n" +
                            "\n" +
                            "2. Wash out its stain, refine its dross,\n" +
                            "Nail my affections to the cross:\n" +
                            "Hallow each thought, let all within\n" +
                            "Be clean, as thou, my Lord, art clean.");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 004 | This song lyrics 4")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 4);
                    intent.putExtra("actionBarTitle", "Song 004");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 005 | This song lyrics 5")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 5);
                    intent.putExtra("actionBarTitle", "Song 005");
                    intent.putExtra("contentTv", "This is song lyrics detail");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 006 | This song lyrics 6")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 6);
                    intent.putExtra("actionBarTitle", "Song 006");
                    intent.putExtra("contentTv", "This is song lyrics detail");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 007 | This song lyrics 7")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 7);
                    intent.putExtra("actionBarTitle", "Song 007");
                    intent.putExtra("contentTv", "This is song lyrics detail");
                    mContext.startActivity(intent);
                }

            }
        });

        return view;
    }

This is the ListViewAdapter.java

public class ListViewAdapter extends BaseAdapter {

    //Variables
    Context mContext;
    LayoutInflater inflater;
    List<Model> modellist;
    ArrayList<Model> arrayList;
    int[] soundfile;

    //Constructor
    public ListViewAdapter(Context context, List<Model> modellist) {
        mContext = context;
        this.modellist = modellist;
        inflater = LayoutInflater.from(mContext);
        this.arrayList = new ArrayList<Model>();
        this.arrayList.addAll(modellist);
    }

    public class ViewHolder {
        TextView mTitleTv, mDescTv;
        ImageView mIconTv, favorite;
    }

    @Override
    public int getCount() {
        return modellist.size();
    }

    @Override
    public Object getItem(int i) {
        return modellist.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(final int i, View view, ViewGroup parent) {
        final ViewHolder holder;
        if (view == null) {
            holder = new ViewHolder();
            view = inflater.inflate(R.layout.row, null);

            //locate the views in row.xml
            holder.mTitleTv = (TextView) view.findViewById(R.id.mainTitle);
            holder.mDescTv = (TextView) view.findViewById(R.id.mainDesc);
            holder.mIconTv = view.findViewById(R.id.mainIcon);
            //initialize the favorite image view
            holder.favorite = view.findViewById(R.id.favorite);

            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }
        //set the result into textview
        holder.mTitleTv.setText(modellist.get(i).getTitle());
        holder.mDescTv.setText(modellist.get(i).getDesc());
        //Set the result in imagview
        holder.mIconTv.setImageResource(modellist.get(i).getIcon());

        if (modellist.get(i).isFavorite())
            holder.favorite.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_heart));
        else
            holder.favorite.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_heart_o));

        //listview soundfile file for songs in position
        soundfile = new int[]{R.raw.song_1, R.raw.song_2, R.raw.song_3, R.raw.song_4, R.raw.song_5, R.raw.song_6, R.raw.song_7, R.raw.song_8,};

        //fovarite/unfavorite

        holder.favorite.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (modellist.get(i).isFavorite())
                    holder.favorite.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_heart_o));
                else
                    holder.favorite.setImageDrawable(mContext.getResources().getDrawable(R.drawable.ic_heart));

                modellist.get(i).setFavorite();
            }
        });

        //listview item clicks
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //code later
                if (modellist.get(i).getTitle().equals("Song 001 | This song lyrics 1")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("actionBarTitle", "Song 001");
                    intent.putExtra("position", 1);
                    intent.putExtra("contentTv", "1. O THOU to whose all-searching sight\n" +
                            "The darkness shineth as the light,\n" +
                            "Search, prove my heart, it pants for thee;\n" +
                            "O burst these bonds and set it free!\n" +
                            "\n" +
                            "2. Wash out its stain, refine its dross,\n" +
                            "Nail my affections to the cross:\n" +
                            "Hallow each thought, let all within\n" +
                            "Be clean, as thou, my Lord, art clean.\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 002 | This song lyrics 2")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 2);
                    intent.putExtra("actionBarTitle", "Song 002");
                    intent.putExtra("contentTv", "3 Saviour, where’er thy steps I see,\n" +
                            "Dauntless, untired, I’ll follow thee;\n" +
                            "O let thy hand support me still\n" +
                            "And lead me to thy holy hill!\n" +
                            "\n" +
                            "4 If rough and thorny be the way,\n" +
                            "My strength proportion to my day,\n" +
                            "Till toil and grief and pain shall cease,\n" +
                            "Where all is calm and joy and peace.\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 003 | This song lyrics 3")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 3);
                    intent.putExtra("actionBarTitle", "Song 003");
                    intent.putExtra("contentTv", "1. O THOU to whose all-searching sight\n" +
                            "The darkness shineth as the light,\n" +
                            "Search, prove my heart, it pants for thee;\n" +
                            "O burst these bonds and set it free!\n" +
                            "\n" +
                            "2. Wash out its stain, refine its dross,\n" +
                            "Nail my affections to the cross:\n" +
                            "Hallow each thought, let all within\n" +
                            "Be clean, as thou, my Lord, art clean.\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 004 | This song lyrics 4")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 4);
                    intent.putExtra("actionBarTitle", "Song 004");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 005 | This song lyrics 5")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 5);
                    intent.putExtra("actionBarTitle", "Song 005");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 006 | This song lyrics 6")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 6);
                    intent.putExtra("actionBarTitle", "Song 006");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }
                if (modellist.get(i).getTitle().equals("Song 007 | This song lyrics 7")) {
                    //start NewActivity with title for actionbar and text for textview
                    Intent intent = new Intent(mContext, NewActivity.class);
                    intent.putExtra("position", 7);
                    intent.putExtra("actionBarTitle", "Song 007");
                    intent.putExtra("contentTv", "This is song lyrics detail\n\n\n\n");
                    mContext.startActivity(intent);
                }

            }
        });

        return view;
    }

    //filter
    public void filter(String charText) {
        charText = charText.toLowerCase(Locale.getDefault());
        modellist.clear();
        if (charText.length() == 0) {
            modellist.addAll(arrayList);
        } else {
            for (Model model : arrayList) {
                if (model.getTitle().toLowerCase(Locale.getDefault()).contains(charText)) {
                    modellist.add(model);
                }
            }
        }
        notifyDataSetChanged();
    }

}

This is the MainActivity.java where i saved the list arrays

public class MainActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {
    private String TAG = "MainActivity ----- ; " ;
    // Store instance variables

    private int page;
    private ConsentForm form;

    ListView listView;
    ListViewAdapter adapter;
    String[] title;
    String[] description;
    int[] icon;
    ArrayList<Model> arrayList = new ArrayList<Model>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //initialize preferences
        PreferenceUtils.initialize(getApplicationContext());

        ActionBar actionBar = getSupportActionBar();
        actionBar.setTitle("Redeemed Songs");

        title = new String[]{"Song 001 | This song lyrics 1","Song 002 | This song lyrics 2","Song 003 | This song lyrics 3","Song 004 | This song lyrics 4","Song 005 | This song lyrics 5","Song 006 | This song lyrics 6","Song 007 | This song lyrics 7"};

        description = new String[]{"MORNING song", "MORNING song", "MORNING song", "MORNING song", "MORNING song", "MORNING song", "MORNING song",};

        icon = new int[]{ R.drawable.song, R.drawable.song, R.drawable.song, R.drawable.song,R.drawable.song,R.drawable.song, R.drawable.song,};

        listView = findViewById(R.id.list);

        for (int i =0; i<title.length; i++){
            Model model =new Model(title[i], description[i], icon[i]);
            //let's simply say, the song identifier is just the order of the song in the list
            model.id = i;
            //bind all strings in an array
            arrayList.add(model);
        }

        //pass result to listview class
        adapter = new ListViewAdapter(this, arrayList);

        //bind the adapter to the listview class
        listView.setAdapter(adapter);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);

        MenuItem myActionMenuItem = menu.findItem(R.id.action_search);
        SearchView searchView = (SearchView)myActionMenuItem.getActionView();
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String s) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String s) {
                if (TextUtils.isEmpty(s)){
                    adapter.filter("");
                    listView.clearTextFilter();
                }
                else {
                    adapter.filter(s);
                }
                return true;
            }
        });

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if (id==R.id.action_settings){
            Toast.makeText(this, "Settings Selected", Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, Main2Activity.class));
            return true;
            //do your funtionality here

        }
        else if (id==R.id.action_howtouse){
                Toast.makeText(this, "How-To", Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, FavoriteListActivity.class));
            return true;
                //do your funtionality here

        }else if (id==R.id.action_favorites){
                Toast.makeText(this, "Favorites Selected", Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, FavoriteListActivity.class));
            return true;
                //do your funtionality here

        }
        else if (id==R.id.action_developers){
            Toast.makeText(this, "About", Toast.LENGTH_SHORT).show();
            startActivity(new Intent(this, Main4Activity.class));
            return true;
            //do your funtionality here

        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        return false;
    }
}

Body:
You can create a List from and String Array in the strings.xml this can then be then be used in and Adapter, you could have a parallel array to match the Song title to Lyrics

But you are probably better using an SQLite database for this type of stuff either directly or Using Android Rooms.

Training material for rooms (which is a layer on top of SQLite) https://developer.android.com/training/data-storage/room/

or more direct https://developer.android.com/training/data-storage/sqlite.html

List<String> myLyricList = Arrays.asList(getResources().getStringArray(R.array.array_lyrics));

List<String> myTitleList = Arrays.asList(getResources().getStringArray(R.array.array_titles));

strings.xml

<string-array name="array_lyrics">
        <item>This song lyrics 1</item>
        <item>This song lyrics 2</item>
</string-array>

<string-array name="array_titles">
        <item>Song 001</item>
        <item>Song 002</item>
</string-array>


来源: stackexchange

问:
How to apply the clustering solution using k-medoids algorithm (for example PAM) to another dataset?
I'm looking for a way to apply the cluster solution from k- medoids algorithm (I'm using PAM) from one sample to another.
I think this could be done for k-means algorithm: for data1, get the centroid from the clustering result; then in data2, for each observation, calculate the distance to each centroid and then assign each observation to its closest centroid. By doing this, we applied the clustering solution from data1 to data2.
However, k- medoids algorithm (for example, PAM) uses medoids as cluster centers instead of means. In this case, it is not clear to me how to apply the clustering solution from one sample to another.
Could anyone help answering this question?
Many thanks!</p>

答:
Clusters are still assigned by distance to the centres, except with k-medoids, the centre is actually a datapoint in the dataset. See code in R below:

```<code>library(ClusterR)
library(ggplot2)
set.seed(100)
# we use the iris data set, split into 2
a = sample(nrow(iris),90)
data_b = iris[-a,1:4]
data_a = iris[a,1:4]

#perform k medoids
cm = Cluster_Medoids(data_a,clusters=3)
</code>```

You can see the medoids are data points:

```<code>cm$medoids
    Sepal.Length Sepal.Width Petal.Length Petal.Width
95           5.6         2.7          4.2         1.3
12           4.8         3.4          1.6         0.2
111          6.5         3.2          5.1         2.0
</code>```

We go ahead and predict:

```<code>pm = predict_Medoids(data_b,MEDOIDS=cm$medoids)
</code>```

And we can calculate distance between medoids from 1st dataset, and assign second dataset to the clusters:

```<code>M = as.matrix(dist(rbind(cm$medoids,data_b)))
labs = sapply(4:nrow(M),function(i)which.min(M[i,1:3]))
</code>```

We check and you can see, the clusters manually calculated agrees with the implemented in clusterR:

```<code>table(pm$clusters==labs)

TRUE
  60
</code>```

We can visualize this:

```<code>PCA = prcomp(rbind(data_a,data_b))$x
plotdf = data.frame(PCA[,1:2],
label=c(cm$clusters,pm$clusters),
dataset=rep(c("train","pred"),c(nrow(data_a),nrow(data_b)))
)

ggplot(plotdf,aes(x=PC1,y=PC2,col=factor(label),shape=dataset)) +
geom_point() + scale_color_brewer(palette="Paired") + theme_bw()
</code>```

ContentLicense: CC BY-SA 4.0

Body:
Clusters are still assigned by distance to the centres, except with k-medoids, the centre is actually a datapoint in the dataset. See code in R below:

library(ClusterR)
library(ggplot2)
set.seed(100)
# we use the iris data set, split into 2
a = sample(nrow(iris),90)
data_b = iris[-a,1:4]
data_a = iris[a,1:4]

#perform k medoids
cm = Cluster_Medoids(data_a,clusters=3)

You can see the medoids are data points:

cm$medoids
    Sepal.Length Sepal.Width Petal.Length Petal.Width
95           5.6         2.7          4.2         1.3
12           4.8         3.4          1.6         0.2
111          6.5         3.2          5.1         2.0

We go ahead and predict:

pm = predict_Medoids(data_b,MEDOIDS=cm$medoids)

And we can calculate distance between medoids from 1st dataset, and assign second dataset to the clusters:

M = as.matrix(dist(rbind(cm$medoids,data_b)))
labs = sapply(4:nrow(M),function(i)which.min(M[i,1:3]))

We check and you can see, the clusters manually calculated agrees with the implemented in clusterR:

table(pm$clusters==labs)

TRUE
  60

We can visualize this:

PCA = prcomp(rbind(data_a,data_b))$x
plotdf = data.frame(PCA[,1:2],
label=c(cm$clusters,pm$clusters),
dataset=rep(c("train","pred"),c(nrow(data_a),nrow(data_b)))
)

ggplot(plotdf,aes(x=PC1,y=PC2,col=factor(label),shape=dataset)) +
geom_point() + scale_color_brewer(palette="Paired") + theme_bw()


问:
spacy-udpipe with pytextrank to extract keywords from non-English text
I've been using pytextrank (https://github.com/DerwenAI/pytextrank/) with spacy and English models for keywords extraction - it works great!

Now I need to process non-English texts and I found udpipe (https://github.com/TakeLab/spacy-udpipe) but it doesn't work out of the box ... after

```<code>nlp = spacy_udpipe.load("sk")
tr = pytextrank.TextRank()
nlp.add_pipe(tr.PipelineComponent, name="textrank", last=True)
doc = nlp(text)
</code>```

I get tokens with POS and DEP tags, but there is nothing in doc._.phrases (doc.noun_chunks is also empty) and in nlp.pipe_names is just ['textrank']

What should I add to the spacy's pipeline to get it working? I assume pytextrank needs noun_chunks...

Any tip or suggestion where to look will help me - thanks!

答:
would you mind starting an issue about this on the PyTextRank repo?
https://github.com/DerwenAI/pytextrank/issues

Also, if you could please provide example text to use (in the language requested)

We'll try to debug this integration.

Thanks for pointing it out!

Paco

Body:
I've been using pytextrank (https://github.com/DerwenAI/pytextrank/) with spacy and English models for keywords extraction - it works great!

Now I need to process non-English texts and I found udpipe (https://github.com/TakeLab/spacy-udpipe) but it doesn't work out of the box ... after

nlp = spacy_udpipe.load("sk")
tr = pytextrank.TextRank()
nlp.add_pipe(tr.PipelineComponent, name="textrank", last=True)
doc = nlp(text)

I get tokens with POS and DEP tags, but there is nothing in doc._.phrases (doc.noun_chunks is also empty) and in nlp.pipe_names is just ['textrank']

What should I add to the spacy's pipeline to get it working? I assume pytextrank needs noun_chunks...

Any tip or suggestion where to look will help me - thanks!


问:
Formatting multiple arguments passed to a function in Java
Often the number of arguments passed to a function can be large. Consider the following case:

```<code>calculate(dataManager.getLastUpdate().getNumberOfChildren(),
          dataManager.getLastUpdate().getNumberOfParents(),
          dataManager.getLastUpdate().getNumberOfGrandChildren(),
          long milliseconds,
          int somethingelse)
</code>```

Is there a guideline in Java that offers a way to align the arguments? Fitting all arguments in a line would not look pretty.

答:
When I have to call a method like this I like to put the arguments on their own line, like so:

```<code>final int result = calculate (
    dataManager.getLastUpdate().getNumberOfChildren(),
    dataManager.getLastUpdate().getNumberOfParents(),
    dataManager.getLastUpdate().getNumberOfGrandChildren(),
    milliseconds,
    somethingelse
);
</code>```

Obviously this is a personal preference, but if you're working with others on code, try to conform to the conventions already set forth.

ContentLicense: CC BY-SA 3.0

Body:
Often the number of arguments passed to a function can be large. Consider the following case:

calculate(dataManager.getLastUpdate().getNumberOfChildren(),
          dataManager.getLastUpdate().getNumberOfParents(),
          dataManager.getLastUpdate().getNumberOfGrandChildren(),
          long milliseconds,
          int somethingelse)

Is there a guideline in Java that offers a way to align the arguments? Fitting all arguments in a line would not look pretty.

Body:
When I have to call a method like this I like to put the arguments on their own line, like so:

final int result = calculate (
    dataManager.getLastUpdate().getNumberOfChildren(),
    dataManager.getLastUpdate().getNumberOfParents(),
    dataManager.getLastUpdate().getNumberOfGrandChildren(),
    milliseconds,
    somethingelse
);

Obviously this is a personal preference, but if you're working with others on code, try to conform to the conventions already set forth.


问:
C - how to add to the end of a char array after realloc()
I have a short char array called "array". I'm trying to realloc more space to it then add more chars onto the end. for some reason when I print the array, these extra characters don't show up, although they do display when I index them individually.

```<code>#include <stdio.h>
#include <stdlib.h>
int main(){
    char *array = malloc(2);
    array[0] = 'b';
    array[1] = '\0';
    char stringToAdd[] = "honey";
    array = realloc(array, (16));
    int pos;
//add stringToAdd into array one char at a time
    for (pos = 0; pos < 5; pos++){
        array[2+pos] = stringToAdd[pos];
        printf("%d ", 2+pos);
        printf("%c ", array[2+pos]);
        printf("%s\n", array);
    }
    array[pos] = '\0';
    int k = sizeof(array);
//should print out the string "bhoney" and its length
    printf("%s, length = %d\n", array,k);
    free(array);
    return 0;
}
</code>```

output is:

```<code>2 h b
3 o b
4 n b
5 e b
6 y b
b, length = 8
</code>```

also the length of the array seems to be 8 no matter how much space I try to realloc to it?

答:
It should be:</p>

```<code>for (pos = 0; pos < 5; pos++){
    array[1+pos] = stringToAdd[pos];
    printf("%d ", 1+pos);
    printf("%c ", array[1+pos]);
    printf("%s\n", array);
}
array[1+pos] = '\0';
</code>```

Body:
I have a short char array called "array". I'm trying to realloc more space to it then add more chars onto the end. for some reason when I print the array, these extra characters don't show up, although they do display when I index them individually.

#include <stdio.h>
#include <stdlib.h>
int main(){
    char *array = malloc(2);
    array[0] = 'b';
    array[1] = '\0';
    char stringToAdd[] = "honey";
    array = realloc(array, (16));
    int pos;
//add stringToAdd into array one char at a time
    for (pos = 0; pos < 5; pos++){
        array[2+pos] = stringToAdd[pos];
        printf("%d ", 2+pos);
        printf("%c ", array[2+pos]);
        printf("%s\n", array);
    }
    array[pos] = '\0';
    int k = sizeof(array);
//should print out the string "bhoney" and its length
    printf("%s, length = %d\n", array,k);
    free(array);
    return 0;
}

output is:

2 h b
3 o b
4 n b
5 e b
6 y b
b, length = 8

also the length of the array seems to be 8 no matter how much space I try to realloc to it?

Body:
It should be:

for (pos = 0; pos < 5; pos++){
    array[1+pos] = stringToAdd[pos];
    printf("%d ", 1+pos);
    printf("%c ", array[1+pos]);
    printf("%s\n", array);
}
array[1+pos] = '\0';


问:
Spark joins performance issue
I'm trying to merge historical and incremental data. As part of the incremental data, I'm getting deletes. Below is the case.

historical data  - 100 records ( 20 columns, id is the key column)

incremental data - 10 records  ( 20 columns, id is the key column)

Out of the 10 records in incremental data, only 5 will match with historical data.

Now I want 100 records in the final dataframe of which 95 records belong to historical data and 5 records belong to incremental data(wherever id column is match).

Update timestamp field is available in both historical and incremental data.

Below is the approach I tried.

```<code>    DF1 - Historical  Data
    DF2 - Incremental Delete Dataset
    DF3 = DF1 LEFTANTIJOIN DF2
    DF4 = DF2 INNERJOIN DF1
    DF5 = DF3 UNION DF4
</code>```

However, I observed It has lot of performance issue as I'm running this join on billions of records. Any better way to do this?

答:
Performance issues are not just related to the size of your data. It depends on many other parameters like, the keys you used for partition, your partitioned file sizes and the cluster configuration you are running your job on. I would recommend you to go through the official documentation on Tuning your spark jobs and make necessary changes.
https://spark.apache.org/docs/latest/tuning.html</p>

Title: Spark joins performance issue

Body:
I'm trying to merge historical and incremental data. As part of the incremental data, I'm getting deletes. Below is the case.

historical data  - 100 records ( 20 columns, id is the key column)

incremental data - 10 records  ( 20 columns, id is the key column)

Out of the 10 records in incremental data, only 5 will match with historical data.

Now I want 100 records in the final dataframe of which 95 records belong to historical data and 5 records belong to incremental data(wherever id column is match).

Update timestamp field is available in both historical and incremental data.

Below is the approach I tried.

    DF1 - Historical  Data
    DF2 - Incremental Delete Dataset
    DF3 = DF1 LEFTANTIJOIN DF2
    DF4 = DF2 INNERJOIN DF1
    DF5 = DF3 UNION DF4

However, I observed It has lot of performance issue as I'm running this join on billions of records. Any better way to do this?


答:
You added the characters after the null terminator. Printing a string stops at the null.

Assign the new characters to array[1+pos] instead of array[2+pos]. This also goes for adding the new null terminator after the loop, it should be

```<code>array[1+pos] = '\0';
</code>```

You could also use strcat() instead of the loop:

```<code>strcat(array, stringToAdd);
</code>```

It will find the null terminator automatically so you don't have to know the offset, and add the new null terminator properly.

sizeof(array) is the size of the pointer (8 bytes), not the length of the string. If you want the string length, you should use strlen(array). See difference between sizeof and strlen in c

Title: C - how to add to the end of a char array after realloc()

Body:
You added the characters after the null terminator. Printing a string stops at the null.

Assign the new characters to array[1+pos] instead of array[2+pos]. This also goes for adding the new null terminator after the loop, it should be

array[1+pos] = '\0';

You could also use strcat() instead of the loop:

strcat(array, stringToAdd);

It will find the null terminator automatically so you don't have to know the offset, and add the new null terminator properly.

sizeof(array) is the size of the pointer (8 bytes), not the length of the string. If you want the string length, you should use strlen(array). See difference between sizeof and strlen in c


问:
What is wrong with my semi-advanced PostgreSQL query? (Related to calculating with times and time intervals.)
Goal:

Have a column (which doesn't exist in the table) representing the number of seconds left until the next time a recurring event is to take place, which is determined by "last done" (timestamptz) combined with the "time span string" column, which is a string such as "7 days" or "25 minutes" or "2 weeks" (standard PG compatible interval strings).

The query:

```<code>SELECT
    *,
    now() - "last done" - "time span string"::interval AS "seconds left until next"
FROM "recurring events"
ORDER BY "seconds left until next" DESC NULLS LAST;
</code>```

The "seconds left until next" column bizarrely gets values such as:

```<code>-1 days +00:32:04.389802
</code>```

Expected value example:

```<code>123456
</code>```

I don't understand why it's not calculating with the columns. It seems to be constructing a string of their values in an interpreted manner or something. I don't know how to describe it.

I've tried to ::integer the AS expression, but that just gives me the error:

```<code>ERROR: cannot cast type interval to integer
</code>```

The question isn't so much about the correct "formula"/order of the actual expression as the fact that it doesn't turn the column (or cell, rather) into an integer (representing the number of seconds left for that event until the next time).

答:
now() - "last done" - "time span string"::interval

In Postgres' date arithmetics, substracting timestamps generates a data of type interval, which is what you are seeing in the result.

You can turn this to seconds with extract():

```<code>extract(epoch from (now() - "last done" - "time span string"::interval))
</code>```

Body:
Goal:

Have a column (which doesn't exist in the table) representing the number of seconds left until the next time a recurring event is to take place, which is determined by "last done" (timestamptz) combined with the "time span string" column, which is a string such as "7 days" or "25 minutes" or "2 weeks" (standard PG compatible interval strings).

The query:

SELECT
    *,
    now() - "last done" - "time span string"::interval AS "seconds left until next"
FROM "recurring events"
ORDER BY "seconds left until next" DESC NULLS LAST;

The "seconds left until next" column bizarrely gets values such as:

-1 days +00:32:04.389802

Expected value example:

123456

I don't understand why it's not calculating with the columns. It seems to be constructing a string of their values in an interpreted manner or something. I don't know how to describe it.

I've tried to ::integer the AS expression, but that just gives me the error:

ERROR: cannot cast type interval to integer

The question isn't so much about the correct "formula"/order of the actual expression as the fact that it doesn't turn the column (or cell, rather) into an integer (representing the number of seconds left for that event until the next time).

Body:
now() - "last done" - "time span string"::interval

In Postgres' date arithmetics, substracting timestamps generates a data of type interval, which is what you are seeing in the result.

You can turn this to seconds with extract():

extract(epoch from (now() - "last done" - "time span string"::interval))


问:
React - How to detect when all sub-components of a parent component are visible to the user?
TL;DR

How can a parent component know when the rendering of every child
  component under it has finished and the DOM visible to the user with its most up to date version?

Let's say I have a component A that has a child Grid component consisting of 3x3 grandchild components. Each of those grandchild components fetches data from a restful API endpoint and renders itself when the data becomes available.

I would like to cover the entire area of Component A with a loader placeholder, to be unveiled only when the last of the components in the grid has fetched the data successfully, and rendered it, such that it's already on the DOM and can be viewed.

The user experience should be a super smooth transition from "loader" to a fully populated grid without flickering.

My problem is knowing exactly when to unveil the components under the loader.

Is there any mechanism I can rely on to do this with absolute accuracy? I don't to hard code a time limit for the loader. As I understand relying on ComponentDidMount for every child is also unreliable as it doesn't actually guarantee the component is fully visible to the user at the time of the call.

To distill the question even further:

I have a component that renders some kind of data. After it's
  initialized it doesn't have it, so in its componentDidMount it hits
  an API endpoint for it. Once it receives the data, it's changing its
  state to reflect it. This understandably causes a re-render of the
  final state of that component. My question is this: How do I know when
  that re-render has taken place and is reflected in the User
  facing DOM. That point in time != the point in time when the
  component's state has changed to contain data.

答:
There are two lifecycle hooks in React that are called after a component's DOM has rendered:

componentDidMount

componentDidUpdate (you're interested in this one)

For your use case your parent component P is interested when N child components have each satisfied some condition X. X can be defined as a sequence:

async operation completed

component has rendered

By combining the state of the component and using the componentDidUpdate hook, you can know when the sequence has completed and your component meets condition X.

You can keep track of when your async operation has completed by setting a state variable. For example:

```<code>this.setState({isFetched: true})
</code>```

After setting state, React will call your components componentDidUpdate function. By comparing the current and previous state objects within this function you can signal to the parent component that your async operation has completed and your new component's state has rendered:

```<code>componentDidUpdate(_prevProps, prevState) {
  if (this.state.isFetched === true && this.state.isFetched !== prevState.isFetched) {
    this.props.componentHasMeaningfullyUpdated()
  }
}
</code>```

In your P component, you can use a counter to keep track of how many children have meaningfully updated:

```<code>function onComponentHasMeaningfullyUpdated() {
  this.setState({counter: this.state.counter + 1})
}
</code>```

Finally, by knowing the length of N you can know when all meaningful updates have occurred and act accordingly in your render method of P:

```<code>const childRenderingFinished = this.state.counter >= N
</code>```

Body:
There are two lifecycle hooks in React that are called after a component's DOM has rendered:

componentDidMount

componentDidUpdate (you're interested in this one)

For your use case your parent component P is interested when N child components have each satisfied some condition X. X can be defined as a sequence:

async operation completed

component has rendered

By combining the state of the component and using the componentDidUpdate hook, you can know when the sequence has completed and your component meets condition X.

You can keep track of when your async operation has completed by setting a state variable. For example:

this.setState({isFetched: true})

After setting state, React will call your components componentDidUpdate function. By comparing the current and previous state objects within this function you can signal to the parent component that your async operation has completed and your new component's state has rendered:

componentDidUpdate(_prevProps, prevState) {
  if (this.state.isFetched === true && this.state.isFetched !== prevState.isFetched) {
    this.props.componentHasMeaningfullyUpdated()
  }
}

In your P component, you can use a counter to keep track of how many children have meaningfully updated:

function onComponentHasMeaningfullyUpdated() {
  this.setState({counter: this.state.counter + 1})
}

Finally, by knowing the length of N you can know when all meaningful updates have occurred and act accordingly in your render method of P:

const childRenderingFinished = this.state.counter >= N


问:
How can I eliminate vertical space between rows of buttons in an HTML table?
I have a div that pops up when the "PATTERNS" button is pressed. This div holds a table of buttons (see pic). I want all of the buttons to be touching however I can't seem to get rid of the row spaces in between them. I am not an experienced html table user.

My research has led me to try the following, is my table layout optimal here?:

.ButtonTable {
  display: block;
  background: rgb(116, 116, 116);
  position: absolute;
  margin: 0;
  padding: 0;
  left: 2%;
  width: 80%;
  height: 70%;
  /*BOX HEIGHT*/
  z-index: 1002;
  overflow: auto;
  opacity: .80;
  filter: alpha(opacity=80);
  border-spacing: 0;
  border-collapse: collapse;
}

.PatternButton {
  border-radius: 4px;
  width: 200px;
  transition-duration: 0.2s;
  color: black;
  background-color: white;
  font-size: 10px;
  font-weight: bold;
  padding: 0;
  margin: 0;
  display: inline-block;
  border: none;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><table className="ButtonTable" cellspacing="0">
  <td className="Col12">
    <th className="Title1">col1</th>
    <button className="PatternButton">1</button><br></br>
    <button className="PatternButton">2</button><br></br>
    <button className="PatternButton">3</button><br></br>
    <button className="PatternButton">4</button><br></br>
    <button className="PatternButton">5</button><br></br>
    <button className="PatternButton">6</button><br></br>
    <th className="Title2">col2</th>
    <button className="PatternButton">1</button><br></br>
    <button className="PatternButton">2</button><br></br>
    <button className="PatternButton">3</button><br></br>
    <button className="PatternButton">4</button><br></br>
    <button className="PatternButton">5</button><br></br>
    <button className="PatternButton">6</button><br></br>
  </td>
  <td className="Col34">
    <th className="Title3">col3</th>
    <button className="PatternButton">1</button><br></br>
    <button className="PatternButton">2</button><br></br>
    <button className="PatternButton">3</button><br></br>
    <button className="PatternButton">4</button><br></br>
    <button className="PatternButton">5</button><br></br>
    <button className="PatternButton">6</button><br></br>
    <th className="Title4">col4</th>
    <button className="PatternButton">1</button><br></br>
    <button className="PatternButton">2</button><br></br>
    <button className="PatternButton">3</button><br></br>
    <button className="PatternButton">4</button><br></br>
    <button className="PatternButton">5</button><br></br>
    <button className="PatternButton">6</button><br></br>
  </td>
  <td className="Col5">
    <th className="Title5">col5</th>
    <button className="PatternButton">1</button><br></br>
    <button className="PatternButton">2</button><br></br>
    <button className="PatternButton">3</button><br></br>
    <button className="PatternButton">4</button><br></br>
    <button className="PatternButton">5</button><br></br>
    <button className="PatternButton">6</button><br></br>
    <button className="PatternButton">7</button><br></br>
    <button className="PatternButton">8</button><br></br>
  </td>
  <td className="Col6">
    <th className="Title6">col6</th>
    <button className="PatternButton">1</button><br></br>
    <button className="PatternButton">2</button><br></br>
    <button className="PatternButton">3</button><br></br>
    <button className="PatternButton">4</button><br></br>
    <button className="PatternButton">5</button><br></br>
    <button className="PatternButton">6</button><br></br>
    <button className="PatternButton">7</button><br></br>
    <button className="PatternButton">8</button><br></br>
  </td>
</table></code>```

答:
Just change the line-height of
 elements to remove row spaces ... like this:

```<code>br {
  line-height: 0;
}
</code>```

Body:
I have a div that pops up when the "PATTERNS" button is pressed. This div holds a table of buttons (see pic). I want all of the buttons to be touching however I can't seem to get rid of the row spaces in between them. I am not an experienced html table user.

My research has led me to try the following, is my table layout optimal here?:

.ButtonTable {
  display: block;
  background: rgb(116, 116, 116);
  position: absolute;
  margin: 0;
  padding: 0;
  left: 2%;
  width: 80%;
  height: 70%;
  /*BOX HEIGHT*/
  z-index: 1002;
  overflow: auto;
  opacity: .80;
  filter: alpha(opacity=80);
  border-spacing: 0;
  border-collapse: collapse;
}

.PatternButton {
  border-radius: 4px;
  width: 200px;
  transition-duration: 0.2s;
  color: black;
  background-color: white;
  font-size: 10px;
  font-weight: bold;
  padding: 0;
  margin: 0;
  display: inline-block;
  border: none;
}

    col1
    <button className="PatternButton">1</button>

    <button className="PatternButton">2</button>

    <button className="PatternButton">3</button>

    <button className="PatternButton">4</button>

    <button className="PatternButton">5</button>

    <button className="PatternButton">6</button>

    col2
    <button className="PatternButton">1</button>

    <button className="PatternButton">2</button>

    <button className="PatternButton">3</button>

    <button className="PatternButton">4</button>

    <button className="PatternButton">5</button>

    <button className="PatternButton">6</button>

    col3
    <button className="PatternButton">1</button>

    <button className="PatternButton">2</button>

    <button className="PatternButton">3</button>

    <button className="PatternButton">4</button>

    <button className="PatternButton">5</button>

    <button className="PatternButton">6</button>

    col4
    <button className="PatternButton">1</button>

    <button className="PatternButton">2</button>

    <button className="PatternButton">3</button>

    <button className="PatternButton">4</button>

    <button className="PatternButton">5</button>

    <button className="PatternButton">6</button>

    col5
    <button className="PatternButton">1</button>

    <button className="PatternButton">2</button>

    <button className="PatternButton">3</button>

    <button className="PatternButton">4</button>

    <button className="PatternButton">5</button>

    <button className="PatternButton">6</button>

    <button className="PatternButton">7</button>

    <button className="PatternButton">8</button>

    col6
    <button className="PatternButton">1</button>

    <button className="PatternButton">2</button>

    <button className="PatternButton">3</button>

    <button className="PatternButton">4</button>

    <button className="PatternButton">5</button>

    <button className="PatternButton">6</button>

    <button className="PatternButton">7</button>

    <button className="PatternButton">8</button>

Body:
Just change the line-height of <br/> elements to remove row spaces ... like this:

br {
  line-height: 0;
}


问:
Entity Framework Core and Cosmos DB. Using LINQ expressions to read entities
In our solution we´re using the package Microsoft.EntityFrameworkCore.Cosmos 3.1.1 to do operations against our cosmos databases and containers in Azure. We have a fairly easy object structure. An object containg a list of other objects.

```<code>public class ExampleEntity : Entity
{
    public string TestProperty { get; set; }
    public IEnumerable<SubEntity> SubEntities { get; set; }

    protected override IEnumerable<object> GetEqualityComponents()
    {
            yield return TestProperty;
    }
}

public class SubEntity : Entity
{
    public bool IsActive { get; set; }

    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return IsActive;
    }
}
</code>```

We´ve configured the DbContext for EntityFramework like this:

```<code>builder.Entity<ExampleEntity>().ToContainer(nameof(ExampleEntity));
builder.Entity<ExampleEntity>().HasKey(p => p.id);
builder.Entity<ExampleEntity>().OwnsMany(p => p.SubEntities);
</code>```

The json structure in cosmos looks like this:

```<code>{
    "id": "51099fa9-5d71-4181-93b1-2c8cc0482a95",
    "CreatedAt": "2020-02-14T08:11:06.701659Z",
    "Discriminator": "ExampleEntity",
    "TestProperty": "Property1",
    "UpdatedAt": "0001-01-01T00:00:00",
    "SubEntities": [
        {
            "id": "9a120613-c42a-4399-a660-e6228cfce0ad",
            "CreatedAt": "2020-02-14T08:11:06.70457Z",
            "ExampleEntityid": "51099fa9-5d71-4181-93b1-2c8cc0482a95",
            "IsActive": false,
            "UpdatedAt": "0001-01-01T00:00:00"
        },
        {
            "id": "21b86b53-2d6a-4b31-a60b-8d31cfd04734",
            "CreatedAt": "2020-02-14T08:11:06.705145Z",
            "ExampleEntityid": "51099fa9-5d71-4181-93b1-2c8cc0482a95",
            "IsActive": true,
            "UpdatedAt": "0001-01-01T00:00:00"
        }
    ],
    "_rid": "R343APAECLsBAAAAAAAAAA==",
    "_self": "dbs/R343AA==/colls/R343APAECLs=/docs/R343APAECLsBAAAAAAAAAA==/",
    "_etag": "\"06001f30-0000-0d00-0000-5e46561b0000\"",
    "_attachments": "attachments/",
    "_ts": 1581667867
}
</code>```

Now, we want to search after ExampleEntities where SubEntities has the boolean value of IsActive set to true. This is where our problems starts.

We have a generic repository, where the Read method looks like this:

```<code>/// <summary>
/// Get an entity from the database
/// </summary>
/// <param name="predicate">A predicate to decide which entity to get</param>
/// <param name="children">Child entities to included in the DbSet</param>
/// <returns>All entities that matches the predicate</returns>
public async Task<IEnumerable<TEntity>> ReadAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] children)
{
    var dbSet = _dbContext.Set<TEntity>();
    children.ToList().ForEach(p => dbSet.Include(p));

    var entities = dbSet.Where(predicate);
    return await entities.ToListAsync();
}
</code>```

Using the following code like this in a IntegrationTest:

```<code>[Test]
public async Task EntityFramework_Should_Return_Object_Based_On_Property_In_SubEntity()
{
    var uow = Container.Resolve<IUnitOfWork<ExampleEntity>>();
    var entity1 = new ExampleEntity
    {
        TestProperty = "Property1",
        SubEntities = new List<SubEntity>
        {
            new SubEntity
            {
                IsActive = false
            },
            new SubEntity
            {
                IsActive = true
            }
        }
    };

    await uow.Repository.CreateAsync(entity1);
    await uow.CommitAsync();

    var readEntity = uow.Repository.ReadAsync(p => p.SubEntities.Any(p => p.IsActive), p => p.SubEntities);
    readEntity.Should().NotBeNull();
}
</code>```

The problem occurs at this line here where I use the Read method from the repository above:

```<code>var readEntity = uow.Repository.ReadAsync(p => p.SubEntities.Any(p => p.IsActive), p => p.SubEntities);
</code>```

It results in the following exception:

```<code>System.InvalidOperationException: The LINQ expression 'DbSet<ExampleEntity>
    .Where(e => EF.Property<IEnumerable<SubEntity>>(e, "SubEntities")
        .AsQueryable()
        .Any(o => o.IsActive))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
</code>```

I find it quite strange that a simple query like this isn´t supported in Entity Framework Cosmos. Obviously I can do a AsEnumerable(), but then I will download all the data from the database and do the filtering client side and not on the database side, which will have a huge performance impact when the database contains 100´000s of records..

How can I rewrite my repository to do such filtering on the database side? Is it possible at all with Entity Framework Cosmos?

答: As per current limitations Include and join are not supported yet.

Body:
In our solution we´re using the package Microsoft.EntityFrameworkCore.Cosmos 3.1.1 to do operations against our cosmos databases and containers in Azure. We have a fairly easy object structure. An object containg a list of other objects.

public class ExampleEntity : Entity
{
    public string TestProperty { get; set; }
    public IEnumerable<SubEntity> SubEntities { get; set; }

    protected override IEnumerable<object> GetEqualityComponents()
    {
            yield return TestProperty;
    }
}

public class SubEntity : Entity
{
    public bool IsActive { get; set; }

    protected override IEnumerable<object> GetEqualityComponents()
    {
        yield return IsActive;
    }
}

We´ve configured the DbContext for EntityFramework like this:

builder.Entity<ExampleEntity>().ToContainer(nameof(ExampleEntity));
builder.Entity<ExampleEntity>().HasKey(p => p.id);
builder.Entity<ExampleEntity>().OwnsMany(p => p.SubEntities);

The json structure in cosmos looks like this:

{
    "id": "51099fa9-5d71-4181-93b1-2c8cc0482a95",
    "CreatedAt": "2020-02-14T08:11:06.701659Z",
    "Discriminator": "ExampleEntity",
    "TestProperty": "Property1",
    "UpdatedAt": "0001-01-01T00:00:00",
    "SubEntities": [
        {
            "id": "9a120613-c42a-4399-a660-e6228cfce0ad",
            "CreatedAt": "2020-02-14T08:11:06.70457Z",
            "ExampleEntityid": "51099fa9-5d71-4181-93b1-2c8cc0482a95",
            "IsActive": false,
            "UpdatedAt": "0001-01-01T00:00:00"
        },
        {
            "id": "21b86b53-2d6a-4b31-a60b-8d31cfd04734",
            "CreatedAt": "2020-02-14T08:11:06.705145Z",
            "ExampleEntityid": "51099fa9-5d71-4181-93b1-2c8cc0482a95",
            "IsActive": true,
            "UpdatedAt": "0001-01-01T00:00:00"
        }
    ],
    "_rid": "R343APAECLsBAAAAAAAAAA==",
    "_self": "dbs/R343AA==/colls/R343APAECLs=/docs/R343APAECLsBAAAAAAAAAA==/",
    "_etag": "\"06001f30-0000-0d00-0000-5e46561b0000\"",
    "_attachments": "attachments/",
    "_ts": 1581667867
}

Now, we want to search after ExampleEntities where SubEntities has the boolean value of IsActive set to true. This is where our problems starts.

We have a generic repository, where the Read method looks like this:

///
/// Get an entity from the database
///
/// <param name="predicate">A predicate to decide which entity to get</param>
/// <param name="children">Child entities to included in the DbSet</param>
/// <returns>All entities that matches the predicate</returns>
public async Task<IEnumerable<TEntity>> ReadAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] children)
{
    var dbSet = _dbContext.Set<TEntity>();
    children.ToList().ForEach(p => dbSet.Include(p));

    var entities = dbSet.Where(predicate);
    return await entities.ToListAsync();
}

Using the following code like this in a IntegrationTest:

[Test]
public async Task EntityFramework_Should_Return_Object_Based_On_Property_In_SubEntity()
{
    var uow = Container.Resolve<IUnitOfWork<ExampleEntity>>();
    var entity1 = new ExampleEntity
    {
        TestProperty = "Property1",
        SubEntities = new List<SubEntity>
        {
            new SubEntity
            {
                IsActive = false
            },
            new SubEntity
            {
                IsActive = true
            }
        }
    };

    await uow.Repository.CreateAsync(entity1);
    await uow.CommitAsync();

    var readEntity = uow.Repository.ReadAsync(p => p.SubEntities.Any(p => p.IsActive), p => p.SubEntities);
    readEntity.Should().NotBeNull();
}

The problem occurs at this line here where I use the Read method from the repository above:

var readEntity = uow.Repository.ReadAsync(p => p.SubEntities.Any(p => p.IsActive), p => p.SubEntities);

It results in the following exception:

System.InvalidOperationException: The LINQ expression 'DbSet<ExampleEntity>
    .Where(e => EF.Property<IEnumerable<SubEntity>>(e, "SubEntities")
        .AsQueryable()
        .Any(o => o.IsActive))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().

I find it quite strange that a simple query like this isn´t supported in Entity Framework Cosmos. Obviously I can do a AsEnumerable(), but then I will download all the data from the database and do the filtering client side and not on the database side, which will have a huge performance impact when the database contains 100´000s of records..

How can I rewrite my repository to do such filtering on the database side? Is it possible at all with Entity Framework Cosmos?


问:
Pygame: The screen flickers when I hold down the mouse, but only a specific button
I have multiple buttons residing in a menu class. The ones I want to point out specifically are the play button and the back button. The play button appears in the "main_menu" state, and when clicked, changes the state to "difficulty_menu". The back button does just the opposite; difficulty menu to main menu. It should be noted that the play button and back button are in two different locations on the screen.

When I hold down the play button, everything works as intended. The button underneath is not clicked and the screen does not flicker. However, when I hold down the back button, the screen flickers rapidly. I either end up in the main menu or the difficulty menu depending on when I release the mouse.

I'm probably overlooking something minor but I just can't figure out what it is. Below is all the code and method calls that are related to the problem. I'm sure other methods aren't an issue because the code for the play and back buttons there are identical.

game.py

```<code>if self.menu.state == "main_menu":
    self.menu.check_hover(mouse)
    if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
        self.menu.check_click(event.pos)
    elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
        self.menu.play_button.l_click = False
elif self.menu.state == "difficulty_menu":
    self.menu.check_hover(mouse)
    if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
        self.menu.check_click(event.pos)
    elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
        self.menu.easy_button.l_click = False
        self.menu.medium_button.l_click = False
        self.menu.hard_button.l_click = False
        self.menu.back_button.l_click = False
</code>```

menu.py

```<code>def check_hover(self, mouse):
    """
    Buttons are checked to see if they are being hovered over.
    If so, the button color changes.
    """
    if self.state == "main_menu":
        self.play_button.check_hover(mouse)
        self.about_button.check_hover(mouse)
        self.credits_button.check_hover(mouse)
        self.quit_button.check_hover(mouse)
    elif self.state == "difficulty_menu":
        self.easy_button.check_hover(mouse)
        self.medium_button.check_hover(mouse)
        self.hard_button.check_hover(mouse)
        self.back_button.check_hover(mouse)

def check_click(self, pos):
    """
    Buttons are checked to see if they have been clicked.
    """
    if self.state == "main_menu":
        self.play_button.check_left_click(pos)
        self.about_button.check_left_click(pos)
        self.credits_button.check_left_click(pos)
        self.quit_button.check_left_click(pos)
    elif self.state == "difficulty_menu":
        self.easy_button.check_left_click(pos)
        self.medium_button.check_left_click(pos)
        self.hard_button.check_left_click(pos)
        self.back_button.check_left_click(pos)

def update(self):
    """
    The state changes depending on if a button has been clicked.
    """
    if self.state == "main_menu":
        if self.play_button.l_click:
            self.state = "difficulty_menu"
        elif self.about_button.l_click:
            self.state = "about_menu"
        elif self.credits_button.l_click:
            self.state = "credits_menu"
        elif self.quit_button.l_click:
            pygame.quit()
            sys.exit()
    elif self.state == "difficulty_menu":
        if self.easy_button.l_click:
            self.difficulty = "easy"
            self.state = "hidden"
        elif self.medium_button.l_click:
            self.difficulty = "medium"
            self.state = "hidden"
        elif self.hard_button.l_click:
            self.difficulty = "hard"
            self.state = "hidden"
        elif self.back_button.l_click:
            self.state = "main_menu"
</code>```

答: I realized what I did wrong. In menu.update(), if l_click is true for the play or back button, I changed the state. Then, in game.py, I'm checking state conditions. The state has already changed so the program never was able to set play_button.l_click or stop_button.l_click to False. I fixed the problem by creating a new method in menu called no_click() that set all button.l_clicks to False. I called this method in every state condition in game.py.</p>

Body:
I have multiple buttons residing in a menu class. The ones I want to point out specifically are the play button and the back button. The play button appears in the "main_menu" state, and when clicked, changes the state to "difficulty_menu". The back button does just the opposite; difficulty menu to main menu. It should be noted that the play button and back button are in two different locations on the screen.

When I hold down the play button, everything works as intended. The button underneath is not clicked and the screen does not flicker. However, when I hold down the back button, the screen flickers rapidly. I either end up in the main menu or the difficulty menu depending on when I release the mouse.

I'm probably overlooking something minor but I just can't figure out what it is. Below is all the code and method calls that are related to the problem. I'm sure other methods aren't an issue because the code for the play and back buttons there are identical.

game.py

if self.menu.state == "main_menu":
    self.menu.check_hover(mouse)
    if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
        self.menu.check_click(event.pos)
    elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
        self.menu.play_button.l_click = False
elif self.menu.state == "difficulty_menu":
    self.menu.check_hover(mouse)
    if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
        self.menu.check_click(event.pos)
    elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
        self.menu.easy_button.l_click = False
        self.menu.medium_button.l_click = False
        self.menu.hard_button.l_click = False
        self.menu.back_button.l_click = False

menu.py

def check_hover(self, mouse):
    """
    Buttons are checked to see if they are being hovered over.
    If so, the button color changes.
    """
    if self.state == "main_menu":
        self.play_button.check_hover(mouse)
        self.about_button.check_hover(mouse)
        self.credits_button.check_hover(mouse)
        self.quit_button.check_hover(mouse)
    elif self.state == "difficulty_menu":
        self.easy_button.check_hover(mouse)
        self.medium_button.check_hover(mouse)
        self.hard_button.check_hover(mouse)
        self.back_button.check_hover(mouse)

def check_click(self, pos):
    """
    Buttons are checked to see if they have been clicked.
    """
    if self.state == "main_menu":
        self.play_button.check_left_click(pos)
        self.about_button.check_left_click(pos)
        self.credits_button.check_left_click(pos)
        self.quit_button.check_left_click(pos)
    elif self.state == "difficulty_menu":
        self.easy_button.check_left_click(pos)
        self.medium_button.check_left_click(pos)
        self.hard_button.check_left_click(pos)
        self.back_button.check_left_click(pos)

def update(self):
    """
    The state changes depending on if a button has been clicked.
    """
    if self.state == "main_menu":
        if self.play_button.l_click:
            self.state = "difficulty_menu"
        elif self.about_button.l_click:
            self.state = "about_menu"
        elif self.credits_button.l_click:
            self.state = "credits_menu"
        elif self.quit_button.l_click:
            pygame.quit()
            sys.exit()
    elif self.state == "difficulty_menu":
        if self.easy_button.l_click:
            self.difficulty = "easy"
            self.state = "hidden"
        elif self.medium_button.l_click:
            self.difficulty = "medium"
            self.state = "hidden"
        elif self.hard_button.l_click:
            self.difficulty = "hard"
            self.state = "hidden"
        elif self.back_button.l_click:
            self.state = "main_menu"


问:
Can't perform I/O in foldr?
I have a Data.Map structure that maps Strings to Stringss. For whatever reason, I want to print the contents of the map in the format key: value using foldrWithKey, like so:

```<code>M.foldrWithKey (\k v b -> putStrLn (k++": "++v++"\n")) (return ()) data
</code>```

However, only the first element of the map appears in the output (even though the map has more than one element). But when I try to construct a list using foldrWithKey and then print it, all of the elements show up:

```<code>print (M.foldrWithKey (\k v b -> k:b) [] data)
</code>```

So, why don't the other elemnts show up when trying to perform I/O? Is it the way foldr works or is there some subtle lazy-io-related quirk that I'm missing?

答:
It's somewhat bad form to intermix IO and pretty printing like that, so how about floating the IO out:

```<code>> putStr $ foldrWithKey (\k v b -> b ++ k ++ ": "++v++"\n") [] m
</code>```

Now, as for why your code isn't working, think about what your fold is building up: a sequence of print statements, in the b parameter. However, you throw away b each time around the loop!

So keep track of it:

```<code>> foldrWithKey (\k v b -> putStrLn (k++": "++v) >> b) (return ()) m
</code>```

Lesson, don't throw away your accumulators.

Title: Can't perform I/O in foldr?

Body:
I have a Data.Map structure that maps Strings to Stringss. For whatever reason, I want to print the contents of the map in the format key: value using foldrWithKey, like so:

M.foldrWithKey (\k v b -> putStrLn (k++": "++v++"\n")) (return ()) data

However, only the first element of the map appears in the output (even though the map has more than one element). But when I try to construct a list using foldrWithKey and then print it, all of the elements show up:

print (M.foldrWithKey (\k v b -> k:b) [] data)

So, why don't the other elemnts show up when trying to perform I/O? Is it the way foldr works or is there some subtle lazy-io-related quirk that I'm missing?

Body:
It's somewhat bad form to intermix IO and pretty printing like that, so how about floating the IO out:

> putStr $ foldrWithKey (\k v b -> b ++ k ++ ": "++v++"\n") [] m

Now, as for why your code isn't working, think about what your fold is building up: a sequence of print statements, in the b parameter. However, you throw away b each time around the loop!

So keep track of it:

> foldrWithKey (\k v b -> putStrLn (k++": "++v) >> b) (return ()) m

Lesson, don't throw away your accumulators.