I have List<List<MyObj>>.
List(1) : List<MyObj>
List(2) : List<MyObj>
List(3) : List<MyObj>
... & so on.
Structure of MyOBj is:
class MyObj {
String name;
String type;
}
I have to get name from MyObj, if type is same for any 2 entries present in List>.
What will be the optimal way to do that in java 7?
List<List<MyObj>> temp = new ArrayList();
sortByType(temp);
List<MyObj> result = new ArrayList();
for (List<MyObj> obj : temp) {
result.add(obj.get(0));
}
Collections.sort(result, new Comparator<MyObj>() {
#Override
public int compare(MyObj o1, MyObj o2) {
return o1.getType() - o2.getType();
}
});
return result.get(0);
private static void sortByType(List<List<MyObj>> result) {
for(List<MyObj> objs : result) {
Collections.sort(objs, new Comparator<MyObj>() {
#Override
public int compare(MyObj o1, MyObj o2) {
return o1.getType() - o2.getType();
}
});
}
}
Related
I am using the enum as the partition key and my model looks like below
#DynamoDbBean
public class Item {
public enum Key {
KEY_A(false),
KEY_B(2),
private final Object defaultValue;
private Key(Object defaultValue) {
this.defaultValue = defaultValue;
}
public Object getDefaultValue() {
return this.defaultValue;
}
}
private Key key;
private Object value;
public Item() {
}
public Item(Key key) {
this.key = key;
this.value = key.getDefaultValue();
}
#DynamoDbConvertedBy(KeyEnumConverter.class)
#DynamoDbPartitionKey
public Key getKey() {
return key;
}
public void setKey(Key key) {
this.key = key;
}
#DynamoDbConvertedBy(ValueConverter.class)
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
My Converter classes to convert between java object and DDB data type is as below:
public class KeyEnumConverter implements AttributeConverter<Item.Key> {
#Override
public AttributeValue transformFrom(Item.Key key) {
return EnhancedAttributeValue.fromString(key.toString()).toAttributeValue();
}
#Override
public Item.Key transformTo(AttributeValue attributeValue) {
return Item.Key.valueOf(attributeValue.s());
}
#Override
public EnhancedType<Item.Key> type() {
return EnhancedType.of(Item.Key.class);
}
#Override
public AttributeValueType attributeValueType() {
return AttributeValueType.S;
}
public class ValueConverter implements AttributeConverter<Object> {
#Override
public AttributeValue transformFrom(Object Value) {
return getEnhancedAttributeValue(Value).toAttributeValue();
}
#Override
public Object transformTo(AttributeValue attributeValue) {
return JsonConvertor.getObjectFromJsonString(attributeValue.s(), Object.class);
}
#Override
public EnhancedType<Object> type() {
return EnhancedType.of(Object.class);
}
#Override
public AttributeValueType attributeValueType() {
return AttributeValueType.S;
}
private EnhancedAttributeValue getEnhancedAttributeValue (Object value) {
if (Value instanceof Boolean) {
return EnhancedAttributeValue.fromBoolean((Boolean)Value);
} else if(value instanceof Number) {
return EnhancedAttributeValue.fromNumber(String.valueOf(value));
} else {
throw new IllegalArgumentException("Please add support for type " + value.getClass().getSimpleName());
}
}
}
When I am putting an item into the table:
public void saveItem (String itemKey) {
Table.putItem(new Item(Item.Key.valueOf(itemKey)));
}
I got the error:
One or more parameter values were invalid: Missing the key id in the item
The partitionKey is defined in the model, why the key id still missing
Here is My AdapterClass AvailablePateientAdapter.java
plaese let me know the how to resolve this issue while scrolling my recyclerview each time increasing the duplicate items
Thanks in advance.
public class AvailablePatientsAdapter extends RecyclerView.Adapter<AvailablePatientsAdapter.AvailablePatientListViewHolder> {
static ReportData patData = null;
private static String niramaiID= null;
static ProgressBar progBar ;
private static ProgressDialog progressDialog;
private static LayoutInflater mInflater = null;
private static ViewPendingList viewPendingList;
private static List<PatientData> patients;
private static Context mContext;
static boolean isPending = false;
int postion;
private static boolean clicked = true;
static String repStatus ;
static Handler viewPatHandler= new Handler(){
#Override
public void handleMessage(Message msg){
patData.setStatusReport(repStatus);
// progressDialog.show();
if(niramaiID != null) {
if (msg.what == 1) {
getexaminationtable(niramaiID);
} else if (msg.what == 2) {
getsegmentationtable(niramaiID);
} else if (msg.what == 3) {
getthanalysistable(niramaiID);
} else if (msg.what == 4) {
Log.d(Config.LOG_TAG, "Response:1 status report " + patData.getStatusReport());
String viewPat = patData.toJson();
Intent addPatFromEdit = new Intent();
addPatFromEdit.setClass(mContext, DisplayReport.class);
addPatFromEdit.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
addPatFromEdit.putExtra("display_report", viewPat);
// addPatFromEdit.putExtra("is_pending",isPending);
if(progressDialog.isShowing()) {
progressDialog.hide();
}
mContext.startActivity(addPatFromEdit);
progBar.setVisibility(View.GONE);
}
}else
{
if(progressDialog.isShowing()) {
progressDialog.hide();
}
Toast.makeText(mContext,"Niramai id is null ",Toast.LENGTH_SHORT).show();
}
}
};
static class AvailablePatientListViewHolder extends RecyclerView.ViewHolder{
private static SimpleDateFormat oudSdf = new SimpleDateFormat("dd-MMM-yyyy");
private static SimpleDateFormat inSdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
AvailablePatientsAdapter mPatientBinding;
ViewPendingList viewPendingList;
AvailablePatientListViewHolder(View itemView) {
super(itemView);
}
// public AvailablePatientListViewHolder(ViewPendingList viewPendingList,View item){
// super(item);
// this.viewPendingList = viewPendingList;
// }
void bind(final PatientData data) {
RelativeLayout b = itemView.findViewById(R.id.rel_available);
niramaiID = data.getNiramaiId();
// progBar.setVisibility(View.VISIBLE);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.postDelayed(new Runnable(){
#Override
public void run() {
Log.d(Config.LOG_TAG," data.getStatus() :: "+data.getStatus());
int muID;
if(NiramaiMythriApplication.getDefaultInt(UNINVERSAL_MUID,mContext) != 0)
{
muID = NiramaiMythriApplication.getDefaultInt(UNINVERSAL_MUID,mContext);
}else
{
muID = LoggedInUser.Users.getDetails().getMu().get(0).getId();
}
getPatientDetails(itemView.getContext(), data.getStatus(),muID ,data.getNiramaiId(),data.getPatientId(), itemView);
progBar.setVisibility(View.GONE);
}
},500);
}
});
TextView patientID = (TextView) itemView.findViewById(R.id.patientID);
TextView scandate = (TextView) itemView.findViewById(R.id.scanDate);
try {
scandate.setText(oudSdf.format(inSdf.parse(data.getScanDate())));
} catch (ParseException e) {
e.printStackTrace();
}
patientID.setText(data.getPatientId());
}
AvailablePatientsAdapter getPatientBinding(){
return this.mPatientBinding;
}
}
public AvailablePatientsAdapter(Context c, #Nullable List<PatientData> p){
mContext=c;
patients = p;
setHasStableIds(true);
progressDialog = new ProgressDialog(mContext);
progressDialog.setTitle("Please wait");
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(false);
}
#Override
public AvailablePatientListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.available_patient_list, parent, false);
mContext = parent.getContext();
progBar = new ProgressBar(parent.getContext());
return new AvailablePatientListViewHolder(itemView);
}
#Override
public void onBindViewHolder(AvailablePatientListViewHolder holder, int position) {
// Log.e("ADAPTER","pos:"+position );
final PatientData p = patients.get(position);
holder.bind(p);
holder.setIsRecyclable(false);
}
#Override
public int getItemCount() {
return patients.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemViewType(int position) {
return position;
}
public void setPatientList(List<PatientData> p, Boolean isPendingActivity){
isPending = isPendingActivity;
patients = p;
notifyDataSetChanged();
}
// Dharam
public void clickOnRecyclerViewItem(boolean click){
clicked = click;
}
private static void getPatientDetails(final Context context, final String status, int muID, String niramaiID, String pID, final View itemView){
if(!progressDialog.isShowing()) {
progressDialog.show();
}
ApiInterface mApiService = RetrofitFactory.getInterfaceService();
Log.d(Config.LOG_TAG,"Call Start muID in Av Report :: "+muID+" niramaiID :: "+niramaiID+" pID :: "+pID);
repStatus = status;
mApiService.getPatientReportData(muID,niramaiID,pID).enqueue(new Callback<ReportData>() {
#Override
public void onResponse(Call<ReportData> call, Response<ReportData> response) {
patData = response.body();
Log.d(Config.LOG_TAG,"patData status color "+ patData);
// progBar.setVisibility(View.VISIBLE);
viewPatHandler.sendEmptyMessage(1);
}
#Override
public void onFailure(Call<ReportData> call, Throwable t) {
// itemView.setClickable(true);
Log.e(Config.LOG_TAG,"An getPatientDetails Error Occured: "+t.getMessage());
}
});
}
private static void getexaminationtable(String niramaiId) {
ApiInterface mApiService = RetrofitFactory.getInterfaceService();
Log.d(Config.LOG_TAG,"getexaminationtable Start");
if(!progressDialog.isShowing()) {
progressDialog.show();
}
mApiService.getExaminationTable(niramaiId).enqueue(new Callback<List<CBEData>>() {
#Override
public void onResponse(Call<List<CBEData>> call, Response<List<CBEData>> response) {
Log.d(Config.LOG_TAG, "Response Body :: "+response.body());
if(response.body() != null && response.body().size()>=1) {
viewPatHandler.sendEmptyMessage(2);
}
}
#Override
public void onFailure(Call<List<CBEData>> call, Throwable t) {
Log.e(Config.LOG_TAG,"An getexaminationtable Error Occured: "+t.getMessage());
}
});
}
private static void getsegmentationtable(String niramaiId) {
ApiInterface mApiService = RetrofitFactory.getInterfaceService();
Log.d(Config.LOG_TAG,"getsegmentationtable Start");
if(!progressDialog.isShowing()) {
progressDialog.show();
}
mApiService.getSegmentationTable(niramaiId).enqueue(new Callback<Object>() {
#Override
public void onResponse(Call<Object> call, Response<Object> response) {
response.body();
viewPatHandler.sendEmptyMessage(3);
}
#Override
public void onFailure(Call<Object> call, Throwable t) {
Log.e(Config.LOG_TAG,"An getsegmentationtable Error Occured: "+t.getMessage());
}
});
}
private static void getthanalysistable(String niramaiId) {
ApiInterface mApiService = RetrofitFactory.getInterfaceService();
Log.d(Config.LOG_TAG,"getthanalysistable Start");
if(!progressDialog.isShowing()) {
progressDialog.show();
}
mApiService.getthanAlysisTable(niramaiId).enqueue(new Callback<Object>() {
#Override
public void onResponse(Call<Object> call, Response<Object> response) {
response.body();
viewPatHandler.sendEmptyMessage(4);
}
#Override
public void onFailure(Call<Object> call, Throwable t) {
Log.e(Config.LOG_TAG,"An getthanalysistable Error Occured: "+t.getMessage());
}
});
}
}
Here is my Activity AvailablePateint.class
can you please let me know also why is it occurring each time while scrolling each time.
public class AvailablePatients extends Activity {
#BindView(R.id.patientsSwipeView) SwipeRefreshLayout swipeContainer;
#BindView(R.id.patientList) RecyclerView patientListView;
#BindView(R.id.searchBox) EditText searchBox;
private Context context;
private boolean clicked;
static String MY_PREFS_NAME = "NIRAMAI_PREFERENCE";
String LOG_TAG = "Niramai";
ApiInterface mApiService;
List<PatientData> allPatientData;
List<PatientData> displayPatientData;
List<PatientData> filteredPatientData;
List<PatientData> availablePatData;
Patients patient;
// List<patient_> patient_ = null;
private AvailablePatientsAdapter mPA;
private user mLoginObject;
// List<IndividualPatient> eachpatient = null;
#BindView(R.id.drawerView) PlaceHolderView mDrawerView;
#BindView(R.id.drawerLayout) DrawerLayout mDrawer;
#BindView(R.id.toolbar_all) Toolbar mToolbar;
int muid = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_final_report);
availablePatData = new ArrayList<>();
context = this;
ButterKnife.bind(this);
mLoginObject = LoggedInUser.Users.getDetails();
if(mLoginObject == null)
{
Toast.makeText(this,"Please Login Again !!",Toast.LENGTH_LONG).show();
Intent myIntent = new Intent(this, LoginActivity.class);
//dharam
myIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY|Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK );
ComponentName cn = myIntent.getComponent();
Intent mainIntent = IntentCompat.makeRestartActivityTask(cn);
startActivity(mainIntent);
finish();
}
SharedPreferences pref = getSharedPreferences("NiramaiPrefrence", Context.MODE_PRIVATE);
if(mLoginObject != null) {
muid = mLoginObject.getMu().get(0).getId();
}
mPA = new AvailablePatientsAdapter(this,new ArrayList<PatientData>());
patientListView.setLayoutManager(new LinearLayoutManager(this,
LinearLayoutManager.VERTICAL,
false));
RecyclerSectionItemDecoration sectionItemDecoration =
new RecyclerSectionItemDecoration(false,getResources().getDimensionPixelSize(R.dimen.recycler_section_header_height),
true,
getSectionCallback());
patientListView.addItemDecoration(sectionItemDecoration);
patientListView.setAdapter(mPA);
searchBox.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
displayPatientData = new ArrayList<>();
if(availablePatData==null) return;
for(PatientData pd : availablePatData){
if (pd.getPatientId().contains(charSequence)){
displayPatientData.add(pd);
}
}
Collections.sort(displayPatientData, new Comparator<PatientData>() {
#Override
public int compare(PatientData p1, PatientData p2) {
return p1.getPatientId().compareTo(p2.getPatientId());
}
});
mPA.setPatientList(displayPatientData,false);
}
#Override
public void afterTextChanged(Editable editable) {
}
});
swipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
swipeContainer.setRefreshing(true);
if(NiramaiMythriApplication.getDefaultInt(UNINVERSAL_MUID,AvailablePatients.this) != 0) {
getAllPatientDataWithRetrofit((NiramaiMythriApplication.getDefaultInt(UNINVERSAL_MUID,AvailablePatients.this)));
}else
{
getAllPatientDataWithRetrofit(muid);
}
}
});
swipeContainer.setRefreshing(true);
if(NiramaiMythriApplication.getDefaultInt(UNINVERSAL_MUID,AvailablePatients.this) != 0) {
getAllPatientDataWithRetrofit((NiramaiMythriApplication.getDefaultInt(UNINVERSAL_MUID,AvailablePatients.this)));
}else
{
getAllPatientDataWithRetrofit(muid);
}
setupDrawer();
}
private RecyclerSectionItemDecoration.SectionCallback getSectionCallback() {
return new RecyclerSectionItemDecoration.SectionCallback() {
#Override
public boolean isSection(int position) {
return false;
}
#Override
public CharSequence getSectionHeader(int position) {
return "Patient ";
}
};
}
private void availablePatData(List<PatientData> patData) {
int j = 0;
Log.d(Config.LOG_TAG, "size" + patData.size());
for (int i = 0; i < patData.size(); i++) {
// Log.d(Config.LOG_TAG, "Patient id" + patData.get(i).getPatientId());
if (patData.get(i).getStatus().equalsIgnoreCase(getResources().getString(R.string.report_status_available)) ||
patData.get(i).getStatus().equalsIgnoreCase(getResources().getString(R.string.report_status_screening_done))) {
availablePatData.add(j,patData.get(i));
j++;
}
}
}
private void getAllPatientDataWithRetrofit(int muID) {
mApiService = RetrofitFactory.getInterfaceService();
Call mService = mApiService.getAllPatients(muID);
mService.enqueue(new Callback<List<Patients>>() {
#Override
public void onResponse(Call<List<Patients>> call, Response<List<Patients>> response) {
if(response.isSuccessful()) {
patient= response.body().get(0);
allPatientData = patient.getPatientData();
try {
filteredPatientData = filterPatients(allPatientData);
} catch (ParseException e) {
e.printStackTrace();
}
availablePatData(filteredPatientData);
displayPatientData = availablePatData;
mPA.setPatientList(displayPatientData,false);
mPA.notifyDataSetChanged();
swipeContainer.setRefreshing(false);
Log.d(LOG_TAG,"Response string is ::: "+ patient.toString());
}
}
#Override
public void onFailure(Call<List<Patients>> call, Throwable t) {
call.cancel();
swipeContainer.setRefreshing(false);
Log.e(LOG_TAG,"getAllPatientDataWithRetrofit process failed in response: "+t.getMessage());
}
});
if(mService.isExecuted())
{
}
}
// Filters All patient to keep only single latest record of each patient id
private List<PatientData> filterPatients(List<PatientData> allPatientData) throws ParseException {
HashMap<String ,Pair<PatientData,Date>> filtered = new HashMap<>();
SimpleDateFormat inSdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
for(PatientData p : allPatientData){
if(filtered.containsKey(p.getPatientId())){
Pair<PatientData,Date> _p = filtered.get(p.getPatientId());
Date d1 = _p.second;
Date d2 = inSdf.parse(p.getScanDate());
if(d2.after(d1)){
filtered.put(p.getPatientId(), new Pair<>(p, d2));
}
}else{
if(p.getScanDate() != null)
filtered.put(p.getPatientId(), new Pair<>(p, inSdf.parse(p.getScanDate())));
}
}
List<Pair<PatientData,Date>> filteredPairs = new ArrayList<>(filtered.values());
Collections.sort(filteredPairs,new Comparator<Pair<PatientData, Date>>() {
#Override
public int compare(Pair<PatientData, Date> t1, Pair<PatientData, Date> t2) {
if(t1.second.after(t2.second)){
return -1;
}else if (t1.second.before(t2.second)){
return 1;
}
else
return t1.first.getPatientId().compareTo(t2.first.getPatientId());
}
});
List<PatientData> filteredList = new ArrayList<>(filteredPairs.size());
for(Pair<PatientData,Date> p : filteredPairs){
filteredList.add(p.first);
}
return filteredList;
}
#Override
protected void onResume() {
super.onResume();
mPA.clickOnRecyclerViewItem(true);
}
#Override
public void onBackPressed() {
super.onBackPressed();
finish();
}
private void setupDrawer(){
mDrawerView
.addView(new DrawerHeader())
.addView(new DrawerMenuItem(this.getApplicationContext(),1))
.addView(new DrawerMenuItem(this.getApplicationContext(),2))
.addView(new DrawerMenuItem(this.getApplicationContext(),3))
.addView(new DrawerMenuItem(this.getApplicationContext(),4));
ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(this, mDrawer, mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close){
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
};
mDrawer.addDrawerListener(drawerToggle);
drawerToggle.syncState();
}
}
Basically when we are adding new item in the list it needs refresh it but while refreshing it you will see the duplicates of the existing items because of previous list was not empty the list had some items. So clear the list first before adding the items in the list.
add the following changes in ActivityPatient.java
private void availablePatData(List<PatientData> patData) {
int j = 0;
if(availablePatData.size()>=0){
availablePatData.clear();
}
Log.d(Config.LOG_TAG, "size" + patData.size());
for (int i = 0; i < patData.size(); i++) {
// Log.d(Config.LOG_TAG, "Patient id" + patData.get(i).getPatientId());
if (patData.get(i).getStatus().equalsIgnoreCase(getResources().getString(R.string.report_status_available)) ||
patData.get(i).getStatus().equalsIgnoreCase(getResources().getString(R.string.report_status_screening_done))) {
availablePatData.add(j,patData.get(i));
j++;
}
}
}
I pass value to property of class in CreateTask, use the property value outside the AsyncTask class, the property value is not change, but the property value change in button click event.
the CreateTask in the AsyncTask class, AsyncTask class have a N property
namespace CreateTask
{
public ref class AsyncTask sealed : INotifyPropertyChanged
{
public:
AsyncTask();
void InitTask();
void ShowN();
IAsyncOperation<float64>^ GetPrimesAsync(float64 x, float64 y);
private:
float64 _n;
bool _isPropertyChangedObserved;
event PropertyChangedEventHandler^ _privatePropertyChanged;
protected:
void OnPropertyChanged(Platform::String^ propertyName)
{
if (_isPropertyChangedObserved)
{
PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName));
}
}
public:
property float64 N
{
float64 get()
{
return _n;
}
void set(float64 value)
{
_n = value;
OnPropertyChanged("N");
}
}
virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged
{
virtual Windows::Foundation::EventRegistrationToken add(Windows::UI::Xaml::Data::PropertyChangedEventHandler^ e)
{
_isPropertyChangedObserved = true;
return _privatePropertyChanged += e;
}
virtual void remove(Windows::Foundation::EventRegistrationToken t)
{
_privatePropertyChanged -= t;
}
protected:
virtual void raise(Object^ sender, Windows::UI::Xaml::Data::PropertyChangedEventArgs^ e)
{
if (_isPropertyChangedObserved)
{
_privatePropertyChanged(sender, e);
}
}
}
};
}
this code is AsyncTask.Cpp
AsyncTask::AsyncTask()
{
InitTask();
}
void AsyncTask::InitTask()
{
create_task(GetPrimesAsync(111.1, 222.2)).then(
[this](float64 z)
{
N = z;
});
}
IAsyncOperation<float64>^ AsyncTask::GetPrimesAsync(float64 x, float64 y)
{
return create_async([this, x, y]() -> float64
{
// Ensure that the input values are in range.
float64 z;
z = x + y;
return z;
});
}
void AsyncTask::ShowN()
{
MessageDialog^ msg = ref new MessageDialog(N.ToString());
msg->ShowAsync();
}
this MainPage.xaml.h code
namespace CreateTask
{
/// <summary>
/// 可用于自身或导航至 Frame 内部的空白页。
/// </summary>
public ref class MainPage sealed
{
public:
MainPage();
private:
AsyncTask^ asyncTask;
private:
void Click_Button(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
};
}
this MainPage.xaml.cpp code
MainPage::MainPage()
{
InitializeComponent();
asyncTask = ref new AsyncTask();
MessageDialog^ msg = ref new MessageDialog(asyncTask->N.ToString());
msg->ShowAsync();
}
void CreateTask::MainPage::Click_Button(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
MessageDialog^ msg = ref new MessageDialog(asyncTask->N.ToString());
msg->ShowAsync();
}
I'm working on a generic collection class template, let's say List(T) where i'd like to be able to do something like php's late static binding. Might be best illustrated with some simplified sample code. This code compiles fine as is on dmd, but it needs a small change to be the way I want.
module main;
import std.stdio;
import std.string;
class List(T)
{
private T[] _list;
public void append(T t)
{
_list ~= t;
}
// this is where some help is needed...
public List select(bool delegate(T t) dg)
{
// auto should be whatever subclass of List(T) is calling this method.
auto result = new List!T();
foreach(t; _list)
{
if (dg(t)) result.append(t);
}
return result;
}
int opApply(int delegate(ref T) dg)
{
int result = 0;
for (int i = 0; i < _list.length; i++)
{
result = dg(_list[i]);
if (result)
break;
}
return result;
}
}
enum Gender
{
MALE,
FEMALE,
SECRET
}
class Person
{
private string _firstName;
private string _lastName;
private string _email;
private Gender _gender;
#property public string firstName() {return _firstName;}
#property public string lastName() {return _lastName;}
#property public string email() {return _email;}
#property public Gender gender() {return _gender;}
public this()
{
}
public this(string firstName, string lastName, Gender gender = Gender.SECRET, string email = "info#example.com")
{
this();
this._firstName = firstName;
this._lastName = lastName;
this._gender = gender;
this._email = email;
}
override public string toString()
{
if (email.length > 0)
{
return "%s %s <%s>".format(firstName, lastName, email);
}
else
{
return "%s %s".format(firstName, lastName);
}
}
}
class PeopleList : List!Person
{
// I would like to be able to make this: public PeopleList selectByGender(Gender gender)
public List!Person selectByGender(Gender gender)
{
return select(p => p.gender == gender);
}
}
void main(string[] args)
{
auto people = new PeopleList();
people.append(new Person("Kris", "Herlaar", Gender.MALE));
people.append(new Person("John", "Doe", Gender.MALE));
people.append(new Person("Steve", "Wozniak", Gender.MALE));
people.append(new Person("Walter", "Bright", Gender.MALE));
people.append(new Person("Amelia", "Earhart", Gender.FEMALE, null));
people.append(new Person("Susan", "Anthony", Gender.FEMALE, null));
foreach(p; people.selectByGender(Gender.FEMALE))
{
writeln(p);
}
}
How would I go about making sure that PeopleList.select would also return an instance of PeopleList instead of a List!Person so that the commented out declaration of selectByGender is correct?
I could probably mock about with Object.factory(this.classinfo.name) inside the implementation and actually get the correct type of instance for result but I figure that would not help with the declared return-type.
I'd want to make chaining methods possible so I'd need the compiler to allow me to return instances of whatever subclass is calling List(T).select I imagine it could be done with a nested template, but haven't been able to come up with anything that would compile, let alone seem elegant.
Additional info in reply to received feedback
I am aware of std.algorithm and of filter, In real life; this code does not represent an actual use-case but a thought experiment to learn more of the abilities/limits of D and its' templates.
This is an unfortunate use of inheritance. PersonList shouldn't exist: It is not in any way polymorhpic.
What I think you intend to do is to provide a helper method: selecting people by gender from a list.
D has something called unified function call syntax, which allows you to call free functions as if the first parameter was the actual this instance. So you could rewrite your code like this:
public List!People selectByGender(List!People list, Gender gender)
{
return list.select(p => p.gender == gender);
}
void main(string[] args)
{
auto people = new List!People();
// ...
foreach(p; people.selectByGender(Gender.FEMALE))
{
writeln(p);
}
}
I don't know if you've looked into std.algorithm yet. But it basically renders all your List(T) code redundant. You could just create an array (or any other range of Person) with your persons and then do:
foreach (p; people.filter!(p => p.gender == Gender.FEMALE))
{
writeln(p);
}
and be done with it. This style resembles (essential elements of) functional programming, pipes and filters or component programming (within the D community), whatever you like to call it. Also filter et al won't allocate a new List, but rather generate their results from the original array on the fly, or lazily, or streaming. You can force them to save the results in a new buffer by using array from std.array.
This is one of the basic cases where forcing yourself to think in Inheritance hierachies is not the most elegant way to go.
You can use Template This Parameters as described in http://dlang.org/template.html#TemplateThisParameter
Here's some example code from the page.
interface Addable(T) {
final R add(this R)(T t) {
return cast(R)this; // cast is necessary, but safe
}
}
class List(T) : Addable!T {
List remove(T t) {
return this;
}
}
void main() {
auto list = new List!int;
list.add(1).remove(1); // ok
}
And here's your code using it.
module main;
import std.stdio;
import std.string;
class List(T)
{
private T[] _list;
public void append(T t)
{
_list ~= t;
}
// select is now templatized based on the most derived class
public This select(this This)(bool delegate(T t) dg)
{
// auto should be whatever subclass of List(T) is calling this method.
auto result = new This();
foreach(t; _list)
{
if (dg(t)) result.append(t);
}
return result;
}
int opApply(int delegate(ref T) dg)
{
int result = 0;
for (int i = 0; i < _list.length; i++)
{
result = dg(_list[i]);
if (result)
break;
}
return result;
}
}
enum Gender
{
MALE,
FEMALE,
SECRET
}
class Person
{
private string _firstName;
private string _lastName;
private string _email;
private Gender _gender;
#property public string firstName() {return _firstName;}
#property public string lastName() {return _lastName;}
#property public string email() {return _email;}
#property public Gender gender() {return _gender;}
public this()
{
}
public this(string firstName, string lastName, Gender gender = Gender.SECRET, string email = "info#example.com")
{
this();
this._firstName = firstName;
this._lastName = lastName;
this._gender = gender;
this._email = email;
}
override public string toString()
{
if (email.length > 0)
{
return "%s %s <%s>".format(firstName, lastName, email);
}
else
{
return "%s %s".format(firstName, lastName);
}
}
}
class PeopleList : List!Person
{
public PeopleList selectByGender(Gender gender)
{
return this.select(p => p.gender == gender);
}
}
void main(string[] args)
{
auto people = new PeopleList();
people.append(new Person("Kris", "Herlaar", Gender.MALE));
people.append(new Person("John", "Doe", Gender.MALE));
people.append(new Person("Steve", "Wozniak", Gender.MALE));
people.append(new Person("Walter", "Bright", Gender.MALE));
people.append(new Person("Amelia", "Earhart", Gender.FEMALE, null));
people.append(new Person("Susan", "Anthony", Gender.FEMALE, null));
foreach(p; people.selectByGender(Gender.FEMALE))
{
writeln(p);
}
}
I am usling IList List property to get a list of students class in University class .. as i try to access this list in department Class which is a part of university class .. the List is Null .. can anyone tell the reason?
namespace UniversitySystem
{
class University : CollectionBase
{
private string _uniName;
Departments _depart = new Departments();
public University(string un, string dn, string cp, List<Student> Slist)
{
this._uniName = un;
this.CED.DepartName = dn;
this.CED.ChairPerson = cp;
foreach (Student s in Slist)
{
List.Add(s);
}
}
#region properties
public string UniName
{
get { return _uniName; }
set { _uniName = value; }
}
public Departments CED
{
get { return _depart; }
set { _depart = value; }
}
#endregion
public class Departments : CollectionBase
{
private string _departName;
public string DepartName
{
get { return _departName; }
set { _departName = value; }
}
private string _chairPerson;
public string ChairPerson
{
get { return _chairPerson; }
set { _chairPerson = value; }
}
public List<Student> StudentListForCED = new List<Student>();
public Departments()
{
_departName = null;
_chairPerson = null;
StudentListForCED = null;
}
public Departments(string dn, string cp, List<Student> Slist)
{
this._departName = dn;
this._chairPerson = cp;
foreach (Student s in Slist)
{
List.Add(s);
}
}
public void showDetails()
{
Console.WriteLine("Departmental Info");
Console.WriteLine("DepartmentName: " + _departName);
Console.WriteLine("Chairperson Name: " + _chairPerson);
Console.WriteLine("Student Info:");
foreach (Student item in List)
{
Console.WriteLine("Name: " + item.Name);
Console.WriteLine("deptName: " + item.RegNo);
Console.WriteLine("total marks: " + item.TotalMarksObtained);
Console.WriteLine("percentage: " + item.GetPercentage());
}
}
}
}
}
THE main() part is
namespace UniversitySystem
{
class Program
{
static void Main(string[] args)
{
List<Student> slist = new List<Student>();
slist.Add(new Student("sana", 1234, "CIS", 650));
slist.Add(new Student("anam", 2345, "BCIT", 400));
slist.Add(new Student("fizzza", 2670, "Electrical", 670));
University u1 = new University("NED", "computer", "UKP", slist);
Console.WriteLine(u1.CED.DepartName);
u1.CED.showDetails();
}
}
}
The initializing code for University does not store the list you give it as a parameter.
try storing the list in a variable in either the department or the university object itself, and when you are showing the details for either of those object you can reference that list, the one you stored upon creating the object.
Hope that helps!
I made a couple changes that should work.
public Departments(string dn, string cp, List<Student> Slist)
{
this._departName = dn;
this._chairPerson = cp;
foreach (Student s in Slist)
{
StudentListForCED.Add(s);
}
}
public void showDetails()
{
Console.WriteLine("Departmental Info");
Console.WriteLine("DepartmentName: " + _departName);
Console.WriteLine("Chairperson Name: " + _chairPerson);
Console.WriteLine("Student Info:");
foreach (Student item in StudentListForCED)
{
Console.WriteLine("Name: " + item.Name);
Console.WriteLine("deptName: " + item.RegNo);
Console.WriteLine("total marks: " + item.TotalMarksObtained);
Console.WriteLine("percentage: " + item.GetPercentage());
}
}
Please read this a little more thoroughly.